1 /* $OpenBSD: cmd-attach-session.c,v 1.30 2014/02/23 00:53:06 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 "attach-session", "attach", 37 "c:drt:", 0, 0, 38 "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, 39 CMD_CANTNEST|CMD_STARTSERVER, 40 NULL, 41 cmd_attach_session_exec 42 }; 43 44 enum cmd_retval 45 cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, 46 const char *cflag) 47 { 48 struct session *s; 49 struct client *c; 50 struct winlink *wl = NULL; 51 struct window *w = NULL; 52 struct window_pane *wp = NULL; 53 const char *update; 54 char *cause; 55 u_int i; 56 int fd; 57 struct format_tree *ft; 58 char *cp; 59 60 if (RB_EMPTY(&sessions)) { 61 cmdq_error(cmdq, "no sessions"); 62 return (CMD_RETURN_ERROR); 63 } 64 65 if (tflag == NULL) { 66 if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) 67 return (CMD_RETURN_ERROR); 68 } else if (tflag[strcspn(tflag, ":.")] != '\0') { 69 if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL) 70 return (CMD_RETURN_ERROR); 71 } else { 72 if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) 73 return (CMD_RETURN_ERROR); 74 w = cmd_lookup_windowid(tflag); 75 if (w == NULL && (wp = cmd_lookup_paneid(tflag)) != NULL) 76 w = wp->window; 77 if (w != NULL) 78 wl = winlink_find_by_window(&s->windows, w); 79 } 80 81 if (cmdq->client == NULL) 82 return (CMD_RETURN_NORMAL); 83 84 if (wl != NULL) { 85 if (wp != NULL) 86 window_set_active_pane(wp->window, wp); 87 session_set_current(s, wl); 88 } 89 90 if (cmdq->client->session != NULL) { 91 if (dflag) { 92 /* 93 * Can't use server_write_session in case attaching to 94 * the same session as currently attached to. 95 */ 96 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 97 c = ARRAY_ITEM(&clients, i); 98 if (c == NULL || c->session != s) 99 continue; 100 if (c == cmdq->client) 101 continue; 102 server_write_client(c, MSG_DETACH, 103 c->session->name, 104 strlen(c->session->name) + 1); 105 } 106 } 107 108 if (cflag != NULL) { 109 ft = format_create(); 110 if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) 111 format_client(ft, c); 112 format_session(ft, s); 113 format_winlink(ft, s, s->curw); 114 format_window_pane(ft, s->curw->window->active); 115 cp = format_expand(ft, cflag); 116 format_free(ft); 117 118 fd = open(cp, O_RDONLY|O_DIRECTORY); 119 free(cp); 120 if (fd == -1) { 121 cmdq_error(cmdq, "bad working directory: %s", 122 strerror(errno)); 123 return (CMD_RETURN_ERROR); 124 } 125 close(s->cwd); 126 s->cwd = fd; 127 } 128 129 cmdq->client->session = s; 130 notify_attached_session_changed(cmdq->client); 131 session_update_activity(s); 132 server_redraw_client(cmdq->client); 133 s->curw->flags &= ~WINLINK_ALERTFLAGS; 134 } else { 135 if (server_client_open(cmdq->client, &cause) != 0) { 136 cmdq_error(cmdq, "open terminal failed: %s", cause); 137 free(cause); 138 return (CMD_RETURN_ERROR); 139 } 140 141 if (cflag != NULL) { 142 ft = format_create(); 143 if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) 144 format_client(ft, c); 145 format_session(ft, s); 146 format_winlink(ft, s, s->curw); 147 format_window_pane(ft, s->curw->window->active); 148 cp = format_expand(ft, cflag); 149 format_free(ft); 150 151 fd = open(cp, O_RDONLY|O_DIRECTORY); 152 free(cp); 153 if (fd == -1) { 154 cmdq_error(cmdq, "bad working directory: %s", 155 strerror(errno)); 156 return (CMD_RETURN_ERROR); 157 } 158 close(s->cwd); 159 s->cwd = fd; 160 } 161 162 if (rflag) 163 cmdq->client->flags |= CLIENT_READONLY; 164 165 if (dflag) { 166 server_write_session(s, MSG_DETACH, s->name, 167 strlen(s->name) + 1); 168 } 169 170 update = options_get_string(&s->options, "update-environment"); 171 environ_update(update, &cmdq->client->environ, &s->environ); 172 173 cmdq->client->session = s; 174 notify_attached_session_changed(cmdq->client); 175 session_update_activity(s); 176 server_redraw_client(cmdq->client); 177 s->curw->flags &= ~WINLINK_ALERTFLAGS; 178 179 server_write_ready(cmdq->client); 180 cmdq->client_exit = 0; 181 } 182 recalculate_sizes(); 183 server_update_socket(); 184 185 return (CMD_RETURN_NORMAL); 186 } 187 188 enum cmd_retval 189 cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) 190 { 191 struct args *args = self->args; 192 193 return (cmd_attach_session(cmdq, args_get(args, 't'), 194 args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'))); 195 } 196