1 /* $OpenBSD: cmd-attach-session.c,v 1.56 2015/12/13 21:53:57 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include "tmux.h" 28 29 /* 30 * Attach existing session to the current terminal. 31 */ 32 33 enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); 34 35 const struct cmd_entry cmd_attach_session_entry = { 36 .name = "attach-session", 37 .alias = "attach", 38 39 .args = { "c:dErt:", 0, 0 }, 40 .usage = "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, 41 42 .flags = CMD_STARTSERVER|CMD_SESSION_T|CMD_PANE_T|CMD_PREFERUNATTACHED, 43 .exec = cmd_attach_session_exec 44 }; 45 46 enum cmd_retval 47 cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag, 48 int Eflag) 49 { 50 struct session *s = cmdq->state.tflag.s; 51 struct client *c = cmdq->client, *c_loop; 52 struct winlink *wl = cmdq->state.tflag.wl; 53 struct window_pane *wp = cmdq->state.tflag.wp; 54 const char *update; 55 char *cause, *cwd; 56 struct format_tree *ft; 57 58 if (RB_EMPTY(&sessions)) { 59 cmdq_error(cmdq, "no sessions"); 60 return (CMD_RETURN_ERROR); 61 } 62 63 if (c == NULL) 64 return (CMD_RETURN_NORMAL); 65 if (server_client_check_nested(c)) { 66 cmdq_error(cmdq, "sessions should be nested with care, " 67 "unset $TMUX to force"); 68 return (CMD_RETURN_ERROR); 69 } 70 71 if (wl != NULL) { 72 if (wp != NULL) 73 window_set_active_pane(wp->window, wp); 74 session_set_current(s, wl); 75 } 76 77 if (cflag != NULL) { 78 ft = format_create(cmdq, 0); 79 format_defaults(ft, c, s, wl, wp); 80 cwd = format_expand(ft, cflag); 81 format_free(ft); 82 83 free((void *)s->cwd); 84 s->cwd = cwd; 85 } 86 87 if (c->session != NULL) { 88 if (dflag) { 89 TAILQ_FOREACH(c_loop, &clients, entry) { 90 if (c_loop->session != s || c == c_loop) 91 continue; 92 server_client_detach(c, MSG_DETACH); 93 } 94 } 95 96 if (!Eflag) { 97 update = options_get_string(s->options, 98 "update-environment"); 99 environ_update(update, c->environ, s->environ); 100 } 101 102 c->session = s; 103 server_client_set_key_table(c, NULL); 104 status_timer_start(c); 105 notify_attached_session_changed(c); 106 session_update_activity(s, NULL); 107 gettimeofday(&s->last_attached_time, NULL); 108 server_redraw_client(c); 109 s->curw->flags &= ~WINLINK_ALERTFLAGS; 110 } else { 111 if (server_client_open(c, &cause) != 0) { 112 cmdq_error(cmdq, "open terminal failed: %s", cause); 113 free(cause); 114 return (CMD_RETURN_ERROR); 115 } 116 117 if (rflag) 118 c->flags |= CLIENT_READONLY; 119 120 if (dflag) { 121 TAILQ_FOREACH(c_loop, &clients, entry) { 122 if (c_loop->session != s || c == c_loop) 123 continue; 124 server_client_detach(c_loop, MSG_DETACH); 125 } 126 } 127 128 if (!Eflag) { 129 update = options_get_string(s->options, 130 "update-environment"); 131 environ_update(update, c->environ, s->environ); 132 } 133 134 c->session = s; 135 server_client_set_key_table(c, NULL); 136 status_timer_start(c); 137 notify_attached_session_changed(c); 138 session_update_activity(s, NULL); 139 gettimeofday(&s->last_attached_time, NULL); 140 server_redraw_client(c); 141 s->curw->flags &= ~WINLINK_ALERTFLAGS; 142 143 if (~c->flags & CLIENT_CONTROL) 144 proc_send(c->peer, MSG_READY, -1, NULL, 0); 145 hooks_run(c->session->hooks, "client-attached", c); 146 cmdq->client_exit = 0; 147 } 148 recalculate_sizes(); 149 alerts_check_session(s); 150 server_update_socket(); 151 152 return (CMD_RETURN_NORMAL); 153 } 154 155 enum cmd_retval 156 cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) 157 { 158 struct args *args = self->args; 159 160 return (cmd_attach_session(cmdq, args_has(args, 'd'), 161 args_has(args, 'r'), args_get(args, 'c'), args_has(args, 'E'))); 162 } 163