cmd-attach-session.c 4.2 KB

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