int cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; struct session *s; enum msgtype msgtype; u_int i; if (args_has(args, 'P')) msgtype = MSG_DETACHKILL; else msgtype = MSG_DETACH; if (args_has(args, 's')) { s = cmd_find_session(ctx, args_get(args, 's'), 0); if (s == NULL) return (-1); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL && c->session == s) server_write_client(c, msgtype, NULL, 0); } } else { c = cmd_find_client(ctx, args_get(args, 't')); if (c == NULL) return (-1); server_write_client(c, msgtype, NULL, 0); } return (0); }
void server_write_error(struct client *c, const char *msg) { struct msg_print_data printdata; strlcpy(printdata.msg, msg, sizeof printdata.msg); server_write_client(c, MSG_ERROR, &printdata, sizeof printdata); }
enum cmd_retval cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c, *c2; struct session *s; enum msgtype msgtype; u_int i; if (args_has(args, 'P')) msgtype = MSG_DETACHKILL; else msgtype = MSG_DETACH; if (args_has(args, 's')) { s = cmd_find_session(cmdq, args_get(args, 's'), 0); if (s == NULL) return (CMD_RETURN_ERROR); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL && c->session == s) server_write_client(c, msgtype, NULL, 0); } } else { c = cmd_find_client(cmdq, args_get(args, 't'), 0); if (c == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c2 = ARRAY_ITEM(&clients, i); if (c2 == NULL || c == c2) continue; server_write_client(c2, msgtype, NULL, 0); } } else server_write_client(c, msgtype, NULL, 0); } return (CMD_RETURN_STOP); }
int cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); server_write_client(c, MSG_DETACH, NULL, 0); return (0); }
int cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct client *c; if ((c = cmd_find_client(ctx, data->target)) == NULL) return (-1); server_write_client(c, MSG_DETACH, NULL, 0); return (0); }
void server_destroy_session(struct session *s) { struct client *c; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; c->session = NULL; server_write_client(c, MSG_EXIT, NULL, 0); } }
enum cmd_retval cmd_suspend_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); tty_stop_tty(&c->tty); c->flags |= CLIENT_SUSPENDED; server_write_client(c, MSG_SUSPEND, NULL, 0); return (CMD_RETURN_NORMAL); }
int cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (-1); tty_stop_tty(&c->tty); c->flags |= CLIENT_SUSPENDED; server_write_client(c, MSG_SUSPEND, NULL, 0); return (0); }
int cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct client *c; if ((c = cmd_find_client(ctx, data->target)) == NULL) return (-1); tty_stop_tty(&c->tty); c->flags |= CLIENT_SUSPENDED; server_write_client(c, MSG_SUSPEND, NULL, 0); return (0); }
void server_write_window( struct window *w, enum hdrtype type, const void *buf, size_t len) { struct client *c; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; if (c->session->curw->window == w) server_write_client(c, type, buf, len); } }
void server_write_session( struct session *s, enum msgtype type, const void *buf, size_t len) { struct client *c; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; if (c->session == s) server_write_client(c, type, buf, len); } }
void cmd_if_shell_free(void *data) { struct cmd_if_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } if (ctx->curclient != NULL) ctx->curclient->references--; xfree(cdata->cmd); xfree(cdata); }
void cmd_run_shell_free(void *data) { struct cmd_run_shell_data *cdata = data; struct cmd_ctx *ctx = &cdata->ctx; struct msg_exit_data exitdata; if (ctx->cmdclient != NULL) { ctx->cmdclient->references--; exitdata.retcode = ctx->cmdclient->retcode; server_write_client( ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata); } if (ctx->curclient != NULL) ctx->curclient->references--; xfree(cdata->cmd); xfree(cdata); }
int cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; char *cause; if (ctx->curclient != NULL) return (0); if (ARRAY_LENGTH(&sessions) == 0) { ctx->error(ctx, "no sessions"); return (-1); } if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { ctx->error(ctx, "not a terminal"); return (-1); } if (tty_open(&ctx->cmdclient->tty, &cause) != 0) { ctx->error(ctx, "terminal open failed: %s", cause); xfree(cause); return (-1); } if (data->flags & CMD_DFLAG) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); recalculate_sizes(); server_redraw_client(ctx->cmdclient); return (1); }
int cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; struct client *c; u_int i; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL && c->session == s) { c->session = NULL; server_write_client(c, MSG_EXIT, NULL, 0); } } recalculate_sizes(); session_destroy(s); return (0); }
enum cmd_retval cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) { struct session *s; struct client *c; const char *update; char *cause; u_int i; if (RB_EMPTY(&sessions)) { cmdq_error(cmdq, "no sessions"); return (CMD_RETURN_ERROR); } if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (CMD_RETURN_ERROR); if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); if (cmdq->client->session != NULL) { if (dflag) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; if (c == cmdq->client) continue; server_write_client(c, MSG_DETACH, NULL, 0); } } cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { if (server_client_open(cmdq->client, s, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } if (rflag) cmdq->client->flags |= CLIENT_READONLY; if (dflag) server_write_session(s, MSG_DETACH, NULL, 0); update = options_get_string(&s->options, "update-environment"); environ_update(update, &cmdq->client->environ, &s->environ); cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; server_write_ready(cmdq->client); cmdq->client_exit = 0; } recalculate_sizes(); server_update_socket(); return (CMD_RETURN_NORMAL); }
int cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_target_data *data = self->data; struct session *s; struct client *c; const char *update; char *overrides, *cause; u_int i; if (ARRAY_LENGTH(&sessions) == 0) { ctx->error(ctx, "no sessions"); return (-1); } if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); if (ctx->cmdclient == NULL && ctx->curclient == NULL) return (0); if (ctx->cmdclient == NULL) { if (cmd_check_flag(data->chflags, 'd')) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; if (c == ctx->curclient) continue; server_write_client(c, MSG_DETACH, NULL, 0); } } ctx->curclient->session = s; server_redraw_client(ctx->curclient); } else { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { ctx->error(ctx, "not a terminal"); return (-1); } overrides = options_get_string(&s->options, "terminal-overrides"); if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { ctx->error(ctx, "terminal open failed: %s", cause); xfree(cause); return (-1); } if (cmd_check_flag(data->chflags, 'r')) ctx->cmdclient->flags |= CLIENT_READONLY; if (cmd_check_flag(data->chflags, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); update = options_get_string(&s->options, "update-environment"); environ_update(update, &ctx->cmdclient->environ, &s->environ); server_redraw_client(ctx->cmdclient); } recalculate_sizes(); server_update_socket(); return (1); /* 1 means don't tell command client to exit */ }
enum cmd_retval cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c, *cloop; struct session *s; enum msgtype msgtype; u_int i; if (self->entry == &cmd_suspend_client_entry) { if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); tty_stop_tty(&c->tty); c->flags |= CLIENT_SUSPENDED; server_write_client(c, MSG_SUSPEND, NULL, 0); return (CMD_RETURN_NORMAL); } if (args_has(args, 'P')) msgtype = MSG_DETACHKILL; else msgtype = MSG_DETACH; if (args_has(args, 's')) { s = cmd_find_session(cmdq, args_get(args, 's'), 0); if (s == NULL) return (CMD_RETURN_ERROR); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { cloop = ARRAY_ITEM(&clients, i); if (cloop == NULL || cloop->session != s) continue; server_write_client(cloop, msgtype, cloop->session->name, strlen(cloop->session->name) + 1); } return (CMD_RETURN_STOP); } c = cmd_find_client(cmdq, args_get(args, 't'), 0); if (c == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { cloop = ARRAY_ITEM(&clients, i); if (cloop == NULL || cloop->session == NULL) continue; if (cloop == c) continue; server_write_client(cloop, msgtype, cloop->session->name, strlen(cloop->session->name) + 1); } return (CMD_RETURN_NORMAL); } server_write_client(c, msgtype, c->session->name, strlen(c->session->name) + 1); return (CMD_RETURN_STOP); }
int cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct session *s, *old_s, *groupwith; struct window *w; struct window_pane *wp; struct environ env; struct termios tio, *tiop; struct passwd *pw; const char *newname, *target, *update, *cwd; char *overrides, *cmd, *cause; int detached, idx; u_int sx, sy, i; newname = args_get(args, 's'); if (newname != NULL && session_find(newname) != NULL) { ctx->error(ctx, "duplicate session: %s", newname); return (-1); } target = args_get(args, 't'); if (target != NULL) { groupwith = cmd_find_session(ctx, target); if (groupwith == NULL) return (-1); } else groupwith = NULL; /* * There are three cases: * * 1. If cmdclient is non-NULL, new-session has been called from the * command-line - cmdclient is to become a new attached, interactive * client. Unless -d is given, the terminal must be opened and then * the client sent MSG_READY. * * 2. If cmdclient is NULL, new-session has been called from an * existing client (such as a key binding). * * 3. Both are NULL, the command was in the configuration file. Treat * this as if -d was given even if it was not. * * In all cases, a new additional session needs to be created and * (unless -d) set as the current session for the client. */ /* Set -d if no client. */ detached = args_has(args, 'd'); if (ctx->cmdclient == NULL && ctx->curclient == NULL) detached = 1; /* * Save the termios settings, part of which is used for new windows in * this session. * * This is read again with tcgetattr() rather than using tty.tio as if * detached, tty_open won't be called. Because of this, it must be done * before opening the terminal as that calls tcsetattr() to prepare for * tmux taking over. */ if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) fatal("tcgetattr failed"); tiop = &tio; } else tiop = NULL; /* Open the terminal if necessary. */ if (!detached && ctx->cmdclient != NULL) { if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) { ctx->error(ctx, "not a terminal"); return (-1); } overrides = options_get_string(&global_s_options, "terminal-overrides"); if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); xfree(cause); return (-1); } } /* Get the new session working directory. */ if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) cwd = ctx->cmdclient->cwd; else { pw = getpwuid(getuid()); if (pw->pw_dir != NULL && *pw->pw_dir != '\0') cwd = pw->pw_dir; else cwd = "/"; } /* Find new session size. */ if (detached) { sx = 80; sy = 24; } else if (ctx->cmdclient != NULL) { sx = ctx->cmdclient->tty.sx; sy = ctx->cmdclient->tty.sy; } else { sx = ctx->curclient->tty.sx; sy = ctx->curclient->tty.sy; } if (sy > 0 && options_get_number(&global_s_options, "status")) sy--; if (sx == 0) sx = 1; if (sy == 0) sy = 1; /* Figure out the command for the new window. */ if (target != NULL) cmd = NULL; else if (args->argc != 0) cmd = args->argv[0]; else cmd = options_get_string(&global_s_options, "default-command"); /* Construct the environment. */ environ_init(&env); update = options_get_string(&global_s_options, "update-environment"); if (ctx->cmdclient != NULL) environ_update(update, &ctx->cmdclient->environ, &env); /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { ctx->error(ctx, "create session failed: %s", cause); xfree(cause); return (-1); } environ_free(&env); /* Set the initial window name if one given. */ if (cmd != NULL && args_has(args, 'n')) { w = s->curw->window; xfree(w->name); w->name = xstrdup(args_get(args, 'n')); options_set_number(&w->options, "automatic-rename", 0); } /* * If a target session is given, this is to be part of a session group, * so add it to the group and synchronize. */ if (groupwith != NULL) { session_group_add(groupwith, s); session_group_synchronize_to(s); session_select(s, RB_ROOT(&s->windows)->idx); } /* * Set the client to the new session. If a command client exists, it is * taking this session and needs to get MSG_READY and stay around. */ if (!detached) { if (ctx->cmdclient != NULL) { server_write_client(ctx->cmdclient, MSG_READY, NULL, 0); old_s = ctx->cmdclient->session; if (old_s != NULL) ctx->cmdclient->last_session = old_s; ctx->cmdclient->session = s; session_update_activity(s); server_redraw_client(ctx->cmdclient); } else { old_s = ctx->curclient->session; if (old_s != NULL) ctx->curclient->last_session = old_s; ctx->curclient->session = s; session_update_activity(s); server_redraw_client(ctx->curclient); } } recalculate_sizes(); server_update_socket(); /* * If there are still configuration file errors to display, put the new * session's current window into more mode and display them now. */ if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) { wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); window_copy_add(wp, "%s", cause); xfree(cause); } ARRAY_FREE(&cfg_causes); } return (!detached); /* 1 means don't tell command client to exit */ }
int cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct session *s; struct client *c; const char *update; char *cause; u_int i; if (RB_EMPTY(&sessions)) { ctx->error(ctx, "no sessions"); return (-1); } if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL) return (-1); if (ctx->cmdclient == NULL && ctx->curclient == NULL) return (0); if (ctx->cmdclient == NULL) { if (args_has(self->args, 'd')) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; if (c == ctx->curclient) continue; server_write_client(c, MSG_DETACH, NULL, 0); } } ctx->curclient->session = s; notify_attached_session_changed(ctx->curclient); session_update_activity(s); server_redraw_client(ctx->curclient); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { if (server_client_open(ctx->cmdclient, s, &cause) != 0) { ctx->error(ctx, "open terminal failed: %s", cause); xfree(cause); return (-1); } if (args_has(self->args, 'r')) ctx->cmdclient->flags |= CLIENT_READONLY; if (args_has(self->args, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); ctx->cmdclient->session = s; notify_attached_session_changed(ctx->cmdclient); session_update_activity(s); server_write_ready(ctx->cmdclient); update = options_get_string(&s->options, "update-environment"); environ_update(update, &ctx->cmdclient->environ, &s->environ); server_redraw_client(ctx->cmdclient); s->curw->flags &= ~WINLINK_ALERTFLAGS; } recalculate_sizes(); server_update_socket(); return (1); /* 1 means don't tell command client to exit */ }
enum cmd_retval cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, const char *cflag) { struct session *s; struct client *c; struct winlink *wl = NULL; struct window *w = NULL; struct window_pane *wp = NULL; const char *update; char *cause; u_int i; int fd; struct format_tree *ft; char *cp; if (RB_EMPTY(&sessions)) { cmdq_error(cmdq, "no sessions"); return (CMD_RETURN_ERROR); } if (tflag == NULL) { if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (CMD_RETURN_ERROR); } else if (tflag[strcspn(tflag, ":.")] != '\0') { if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL) return (CMD_RETURN_ERROR); } else { if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (CMD_RETURN_ERROR); w = cmd_lookup_windowid(tflag); if (w == NULL && (wp = cmd_lookup_paneid(tflag)) != NULL) w = wp->window; if (w != NULL) wl = winlink_find_by_window(&s->windows, w); } if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); if (wl != NULL) { if (wp != NULL) window_set_active_pane(wp->window, wp); session_set_current(s, wl); } if (cmdq->client->session != NULL) { if (dflag) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; if (c == cmdq->client) continue; server_write_client(c, MSG_DETACH, c->session->name, strlen(c->session->name) + 1); } } if (cflag != NULL) { ft = format_create(); if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, s->curw); format_window_pane(ft, s->curw->window->active); cp = format_expand(ft, cflag); format_free(ft); fd = open(cp, O_RDONLY|O_DIRECTORY); free(cp); if (fd == -1) { cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } close(s->cwd); s->cwd = fd; } cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { if (server_client_open(cmdq->client, s, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } if (cflag != NULL) { ft = format_create(); if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, s->curw); format_window_pane(ft, s->curw->window->active); cp = format_expand(ft, cflag); format_free(ft); fd = open(cp, O_RDONLY|O_DIRECTORY); free(cp); if (fd == -1) { cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } close(s->cwd); s->cwd = fd; } if (rflag) cmdq->client->flags |= CLIENT_READONLY; if (dflag) { server_write_session(s, MSG_DETACH, s->name, strlen(s->name) + 1); } update = options_get_string(&s->options, "update-environment"); environ_update(update, &cmdq->client->environ, &s->environ); cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; server_write_ready(cmdq->client); cmdq->client_exit = 0; } recalculate_sizes(); server_update_socket(); return (CMD_RETURN_NORMAL); }