tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

server-fn.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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 #include <sys/wait.h>
21 #include <sys/uio.h>
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27 
28 #include "tmux.h"
29 
30 static struct session *server_next_session(struct session *);
31 static void server_destroy_session_group(struct session *);
32 
33 void
35 {
37 }
38 
39 void
41 {
43 }
44 
45 void
47 {
48  struct client *c;
49 
50  TAILQ_FOREACH(c, &clients, entry) {
51  if (c->session == s)
53  }
54 }
55 
56 void
58 {
59  struct session_group *sg;
60 
61  if ((sg = session_group_contains(s)) == NULL)
63  else {
64  TAILQ_FOREACH(s, &sg->sessions, gentry)
66  }
67 }
68 
69 void
71 {
72  struct client *c;
73 
74  TAILQ_FOREACH(c, &clients, entry) {
75  if (c->session == s)
77  }
78 }
79 
80 void
82 {
83  struct session_group *sg;
84 
85  if ((sg = session_group_contains(s)) == NULL)
87  else {
88  TAILQ_FOREACH(s, &sg->sessions, gentry)
90  }
91 }
92 
93 void
95 {
96  struct client *c;
97 
98  TAILQ_FOREACH(c, &clients, entry) {
99  if (c->session != NULL && c->session->curw->window == w)
101  }
102 }
103 
104 void
106 {
107  struct client *c;
108 
109  TAILQ_FOREACH(c, &clients, entry) {
110  if (c->session != NULL && c->session->curw->window == w)
112  }
113 }
114 
115 void
117 {
118  struct session *s;
119 
120  /*
121  * This is slightly different. We want to redraw the status line of any
122  * clients containing this window rather than anywhere it is the
123  * current window.
124  */
125 
126  RB_FOREACH(s, sessions, &sessions) {
127  if (session_has(s, w))
129  }
130 }
131 
132 void
134 {
135  struct client *c;
136 
137  TAILQ_FOREACH(c, &clients, entry) {
138  if (c->session != NULL)
140  }
141 }
142 
143 void
145 {
146  struct client *c;
147 
148  TAILQ_FOREACH(c, &clients, entry) {
149  if (c->session == s)
151  }
152 }
153 
154 void
156 {
157  const char *cmd;
158 
159  if (c->flags & CLIENT_CONTROL)
160  return;
161 
162  if (c->flags & CLIENT_SUSPENDED)
163  return;
164 
165  cmd = options_get_string(c->session->options, "lock-command");
166  if (*cmd == '\0' || strlen(cmd) + 1 > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
167  return;
168 
169  tty_stop_tty(&c->tty);
173 
174  c->flags |= CLIENT_SUSPENDED;
175  proc_send(c->peer, MSG_LOCK, -1, cmd, strlen(cmd) + 1);
176 }
177 
178 void
180 {
181  struct window *w = wp->window;
182 
183  if (window_count_panes(w) == 1) {
184  server_kill_window(w, 1);
186  } else {
189  layout_close_pane(wp);
190  window_remove_pane(w, wp);
192  }
193 }
194 
195 void
196 server_kill_window(struct window *w, int renumber)
197 {
198  struct session *s, *s1;
199  struct winlink *wl;
200 
201  RB_FOREACH_SAFE(s, sessions, &sessions, s1) {
202  if (!session_has(s, w))
203  continue;
204 
206  while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
207  if (session_detach(s, wl)) {
209  break;
210  } else
212  }
213 
214  if (renumber)
216  }
218 }
219 
220 void
222 {
223  struct session_group *sg;
224 
225  if (options_get_number(s->options, "renumber-windows")) {
226  if ((sg = session_group_contains(s)) != NULL) {
227  TAILQ_FOREACH(s, &sg->sessions, gentry)
229  } else
231  }
232 }
233 
234 void
236 {
237  struct session *s;
238 
239  RB_FOREACH(s, sessions, &sessions)
241 }
242 
243 int
244 server_link_window(struct session *src, struct winlink *srcwl,
245  struct session *dst, int dstidx, int killflag, int selectflag,
246  char **cause)
247 {
248  struct winlink *dstwl;
249  struct session_group *srcsg, *dstsg;
250 
251  srcsg = session_group_contains(src);
252  dstsg = session_group_contains(dst);
253  if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
254  xasprintf(cause, "sessions are grouped");
255  return (-1);
256  }
257 
258  dstwl = NULL;
259  if (dstidx != -1)
260  dstwl = winlink_find_by_index(&dst->windows, dstidx);
261  if (dstwl != NULL) {
262  if (dstwl->window == srcwl->window) {
263  xasprintf(cause, "same index: %d", dstidx);
264  return (-1);
265  }
266  if (killflag) {
267  /*
268  * Can't use session_detach as it will destroy session
269  * if this makes it empty.
270  */
271  notify_session_window("window-unlinked", dst,
272  dstwl->window);
273  dstwl->flags &= ~~WINLINK_ALERTFLAGS;
274  winlink_stack_remove(&dst->lastw, dstwl);
275  winlink_remove(&dst->windows, dstwl);
276 
277  /* Force select/redraw if current. */
278  if (dstwl == dst->curw) {
279  selectflag = 1;
280  dst->curw = NULL;
281  }
282  }
283  }
284 
285  if (dstidx == -1)
286  dstidx = -1 - options_get_number(dst->options, "base-index");
287  dstwl = session_attach(dst, srcwl->window, dstidx, cause);
288  if (dstwl == NULL)
289  return (-1);
290 
291  if (selectflag)
292  session_select(dst, dstwl->idx);
294 
295  return (0);
296 }
297 
298 void
299 server_unlink_window(struct session *s, struct winlink *wl)
300 {
301  if (session_detach(s, wl))
303  else
305 }
306 
307 void
308 server_destroy_pane(struct window_pane *wp, int notify)
309 {
310  struct window *w = wp->window;
311  struct screen_write_ctx ctx;
312  struct grid_cell gc;
313  time_t t;
314  char tim[26];
315  int remain_on_exit;
316 
317  if (wp->fd != -1) {
318 #ifdef HAVE_UTEMPTER
319  utempter_remove_record(wp->fd);
320 #endif
321  bufferevent_free(wp->event);
322  wp->event = NULL;
323  close(wp->fd);
324  wp->fd = -1;
325  }
326 
327  remain_on_exit = options_get_number(wp->options, "remain-on-exit");
328  if (remain_on_exit != 0 && (~wp->flags & PANE_STATUSREADY))
329  return;
330  switch (remain_on_exit) {
331  case 0:
332  break;
333  case 2:
334  if (WIFEXITED(wp->status) && WEXITSTATUS(wp->status) == 0)
335  break;
336  /* FALLTHROUGH */
337  case 1:
338  if (wp->flags & PANE_STATUSDRAWN)
339  return;
340  wp->flags |= PANE_STATUSDRAWN;
341 
342  if (notify)
343  notify_pane("pane-died", wp);
344 
345  screen_write_start_pane(&ctx, wp, &wp->base);
346  screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1);
347  screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1, 0);
348  screen_write_linefeed(&ctx, 1, 8);
349  memcpy(&gc, &grid_default_cell, sizeof gc);
350 
351  time(&t);
352  ctime_r(&t, tim);
353  tim[strcspn(tim, "\n")] = '\0';
354 
355  if (WIFEXITED(wp->status)) {
356  screen_write_nputs(&ctx, -1, &gc,
357  "Pane is dead (status %d, %s)",
358  WEXITSTATUS(wp->status),
359  tim);
360  } else if (WIFSIGNALED(wp->status)) {
361  screen_write_nputs(&ctx, -1, &gc,
362  "Pane is dead (signal %s, %s)",
363  sig2name(WTERMSIG(wp->status)),
364  tim);
365  }
366 
367  screen_write_stop(&ctx);
368  wp->flags |= PANE_REDRAW;
369  return;
370  }
371 
372  if (notify)
373  notify_pane("pane-exited", wp);
374 
377  layout_close_pane(wp);
378  window_remove_pane(w, wp);
379 
380  if (TAILQ_EMPTY(&w->panes))
381  server_kill_window(w, 1);
382  else
384 }
385 
386 static void
388 {
389  struct session_group *sg;
390  struct session *s1;
391 
392  if ((sg = session_group_contains(s)) == NULL)
394  else {
395  TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
397  session_destroy(s, 1, __func__);
398  }
399  }
400 }
401 
402 static struct session *
404 {
405  struct session *s_loop, *s_out = NULL;
406 
407  RB_FOREACH(s_loop, sessions, &sessions) {
408  if (s_loop == s)
409  continue;
410  if (s_out == NULL ||
411  timercmp(&s_loop->activity_time, &s_out->activity_time, <))
412  s_out = s_loop;
413  }
414  return (s_out);
415 }
416 
417 static struct session *
419 {
420  struct session *s_loop, *s_out = NULL;
421 
422  RB_FOREACH(s_loop, sessions, &sessions) {
423  if (s_loop == s || s_loop->attached)
424  continue;
425  if (s_out == NULL ||
426  timercmp(&s_loop->activity_time, &s_out->activity_time, <))
427  s_out = s_loop;
428  }
429  return (s_out);
430 }
431 
432 void
434 {
435  struct client *c;
436  struct session *s_new;
437  int detach_on_destroy;
438 
439  detach_on_destroy = options_get_number(s->options, "detach-on-destroy");
440  if (detach_on_destroy == 0)
441  s_new = server_next_session(s);
442  else if (detach_on_destroy == 2)
443  s_new = server_next_detached_session(s);
444  else
445  s_new = NULL;
446  TAILQ_FOREACH(c, &clients, entry) {
447  if (c->session != s)
448  continue;
449  if (s_new == NULL) {
450  c->session = NULL;
451  c->flags |= CLIENT_EXIT;
452  } else {
453  c->last_session = NULL;
454  c->session = s_new;
458  notify_client("client-session-changed", c);
459  session_update_activity(s_new, NULL);
460  gettimeofday(&s_new->last_attached_time, NULL);
462  alerts_check_session(s_new);
463  }
464  }
466 }
467 
468 void
470 {
471  struct session *s;
472 
473  /*
474  * If any sessions are no longer attached and have destroy-unattached
475  * set, collect them.
476  */
477  RB_FOREACH(s, sessions, &sessions) {
478  if (s->attached != 0)
479  continue;
480  if (options_get_number (s->options, "destroy-unattached"))
481  session_destroy(s, 1, __func__);
482  }
483 }
484 
485 void
487 {
488  if (window_unzoom(w) == 0)
490 }
void alerts_check_session(struct session *s)
Definition: alerts.c:103
#define timercmp(tvp, uvp, cmp)
Definition: compat.h:230
const struct grid_cell grid_default_cell
Definition: grid.c:39
void layout_close_pane(struct window_pane *wp)
Definition: layout.c:1037
void notify_session_window(const char *name, struct session *s, struct window *w)
Definition: notify.c:244
void notify_client(const char *name, struct client *c)
Definition: notify.c:214
void notify_pane(const char *name, struct window_pane *wp)
Definition: notify.c:262
const char * options_get_string(struct options *oo, const char *name)
Definition: options.c:686
long long options_get_number(struct options *oo, const char *name)
Definition: options.c:699
int proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf, size_t len)
Definition: proc.c:162
void recalculate_sizes(void)
Definition: resize.c:355
void screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper, u_int rlower)
void screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
void screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s)
Definition: screen-write.c:251
void screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py, int origin)
void screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen, const struct grid_cell *gcp, const char *fmt,...)
Definition: screen-write.c:476
void screen_write_stop(struct screen_write_ctx *ctx)
Definition: screen-write.c:296
void server_client_set_key_table(struct client *c, const char *name)
void server_client_remove_pane(struct window_pane *wp)
void server_lock(void)
Definition: server-fn.c:133
void server_redraw_window_borders(struct window *w)
Definition: server-fn.c:105
void server_status_session_group(struct session *s)
Definition: server-fn.c:81
void server_redraw_session(struct session *s)
Definition: server-fn.c:46
void server_destroy_pane(struct window_pane *wp, int notify)
Definition: server-fn.c:308
void server_check_unattached(void)
Definition: server-fn.c:469
void server_renumber_all(void)
Definition: server-fn.c:235
void server_destroy_session(struct session *s)
Definition: server-fn.c:433
void server_redraw_client(struct client *c)
Definition: server-fn.c:34
int server_link_window(struct session *src, struct winlink *srcwl, struct session *dst, int dstidx, int killflag, int selectflag, char **cause)
Definition: server-fn.c:244
static struct session * server_next_detached_session(struct session *s)
Definition: server-fn.c:418
void server_status_window(struct window *w)
Definition: server-fn.c:116
static void server_destroy_session_group(struct session *)
Definition: server-fn.c:387
void server_unlink_window(struct session *s, struct winlink *wl)
Definition: server-fn.c:299
static struct session * server_next_session(struct session *)
Definition: server-fn.c:403
void server_lock_session(struct session *s)
Definition: server-fn.c:144
void server_kill_window(struct window *w, int renumber)
Definition: server-fn.c:196
void server_status_client(struct client *c)
Definition: server-fn.c:40
void server_renumber_session(struct session *s)
Definition: server-fn.c:221
void server_redraw_window(struct window *w)
Definition: server-fn.c:94
void server_unzoom_window(struct window *w)
Definition: server-fn.c:486
void server_redraw_session_group(struct session *s)
Definition: server-fn.c:57
void server_lock_client(struct client *c)
Definition: server-fn.c:155
void server_status_session(struct session *s)
Definition: server-fn.c:70
void server_kill_pane(struct window_pane *wp)
Definition: server-fn.c:179
struct clients clients
Definition: server.c:42
struct sessions sessions
Definition: session.c:29
struct session_group * session_group_contains(struct session *target)
Definition: session.c:505
int session_select(struct session *s, int idx)
Definition: session.c:461
void session_update_activity(struct session *s, struct timeval *from)
Definition: session.c:266
struct winlink * session_attach(struct session *s, struct window *w, int idx, char **cause)
Definition: session.c:331
void session_destroy(struct session *s, int notify, const char *from)
Definition: session.c:201
int session_detach(struct session *s, struct winlink *wl)
Definition: session.c:349
int session_has(struct session *s, struct window *w)
Definition: session.c:372
void session_renumber_windows(struct session *s)
Definition: session.c:694
void status_timer_start(struct client *c)
Definition: status.c:172
Definition: tmux.h:1608
struct tty tty
Definition: tmux.h:1640
struct session * last_session
Definition: tmux.h:1744
struct session * session
Definition: tmux.h:1743
uint64_t flags
Definition: tmux.h:1703
struct tmuxpeer * peer
Definition: tmux.h:1610
Definition: cmd.c:212
struct screen * s
Definition: tmux.h:851
Definition: tmux.h:1179
struct timeval last_attached_time
Definition: tmux.h:1186
struct winlinks windows
Definition: tmux.h:1194
struct winlink_stack lastw
Definition: tmux.h:1193
struct timeval activity_time
Definition: tmux.h:1187
struct winlink * curw
Definition: tmux.h:1192
struct options * options
Definition: tmux.h:1199
u_int attached
Definition: tmux.h:1205
struct tty_term * term
Definition: tmux.h:1357
int fd
Definition: tmux.h:1001
int status
Definition: tmux.h:999
int flags
Definition: tmux.h:977
struct screen base
Definition: tmux.h:1021
struct bufferevent * event
Definition: tmux.h:1002
struct window * window
Definition: tmux.h:962
struct options * options
Definition: tmux.h:963
Definition: tmux.h:1041
struct window_panes panes
Definition: tmux.h:1056
const char * sig2name(int signo)
Definition: tmux.c:261
@ TTYC_E3
Definition: tmux.h:311
@ TTYC_SMCUP
Definition: tmux.h:488
@ TTYC_CLEAR
Definition: tmux.h:284
#define PANE_STATUSREADY
Definition: tmux.h:987
void tty_raw(struct tty *, const char *)
Definition: tty.c:470
@ MSG_LOCK
Definition: tmux.h:528
const char * tty_term_string(struct tty_term *, enum tty_code_code)
Definition: tty-term.c:752
void tty_stop_tty(struct tty *)
Definition: tty.c:362
void winlink_stack_remove(struct winlink_stack *, struct winlink *)
Definition: window.c:251
#define CLIENT_CONTROL
Definition: tmux.h:1667
#define PANE_STATUSDRAWN
Definition: tmux.h:988
#define screen_size_y(s)
Definition: tmux.h:882
#define PANE_REDRAW
Definition: tmux.h:978
#define CLIENT_ALLREDRAWFLAGS
Definition: tmux.h:1688
#define CLIENT_REDRAWSTATUS
Definition: tmux.h:1658
#define CLIENT_REDRAWBORDERS
Definition: tmux.h:1664
void winlink_remove(struct winlinks *, struct winlink *)
Definition: window.c:193
struct winlink * winlink_find_by_window(struct winlinks *, struct window *)
Definition: window.c:96
int window_unzoom(struct window *)
Definition: window.c:611
struct winlink * winlink_find_by_index(struct winlinks *, int)
Definition: window.c:109
void tty_update_client_offset(struct client *)
Definition: tty.c:868
#define CLIENT_SUSPENDED
Definition: tmux.h:1660
u_int window_count_panes(struct window *)
Definition: window.c:773
#define CLIENT_EXIT
Definition: tmux.h:1656
void window_remove_pane(struct window *, struct window_pane *)
Definition: window.c:709
int xasprintf(char **ret, const char *fmt,...)
Definition: xmalloc.c:109