xref: /openbsd-src/usr.bin/tmux/cmd.c (revision ac9b4aacc1da35008afea06a5d23c2f2dea9b93e)
1 /* $OpenBSD: cmd.c,v 1.70 2012/09/03 09:57: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 #include <sys/time.h>
21 
22 #include <fnmatch.h>
23 #include <paths.h>
24 #include <pwd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "tmux.h"
30 
31 const struct cmd_entry *cmd_table[] = {
32 	&cmd_attach_session_entry,
33 	&cmd_bind_key_entry,
34 	&cmd_break_pane_entry,
35 	&cmd_capture_pane_entry,
36 	&cmd_choose_buffer_entry,
37 	&cmd_choose_client_entry,
38 	&cmd_choose_list_entry,
39 	&cmd_choose_session_entry,
40 	&cmd_choose_tree_entry,
41 	&cmd_choose_window_entry,
42 	&cmd_clear_history_entry,
43 	&cmd_clock_mode_entry,
44 	&cmd_command_prompt_entry,
45 	&cmd_confirm_before_entry,
46 	&cmd_copy_mode_entry,
47 	&cmd_delete_buffer_entry,
48 	&cmd_detach_client_entry,
49 	&cmd_display_message_entry,
50 	&cmd_display_panes_entry,
51 	&cmd_find_window_entry,
52 	&cmd_has_session_entry,
53 	&cmd_if_shell_entry,
54 	&cmd_join_pane_entry,
55 	&cmd_kill_pane_entry,
56 	&cmd_kill_server_entry,
57 	&cmd_kill_session_entry,
58 	&cmd_kill_window_entry,
59 	&cmd_last_pane_entry,
60 	&cmd_last_window_entry,
61 	&cmd_link_window_entry,
62 	&cmd_list_buffers_entry,
63 	&cmd_list_clients_entry,
64 	&cmd_list_commands_entry,
65 	&cmd_list_keys_entry,
66 	&cmd_list_panes_entry,
67 	&cmd_list_sessions_entry,
68 	&cmd_list_windows_entry,
69 	&cmd_load_buffer_entry,
70 	&cmd_lock_client_entry,
71 	&cmd_lock_server_entry,
72 	&cmd_lock_session_entry,
73 	&cmd_move_pane_entry,
74 	&cmd_move_window_entry,
75 	&cmd_new_session_entry,
76 	&cmd_new_window_entry,
77 	&cmd_next_layout_entry,
78 	&cmd_next_window_entry,
79 	&cmd_paste_buffer_entry,
80 	&cmd_pipe_pane_entry,
81 	&cmd_previous_layout_entry,
82 	&cmd_previous_window_entry,
83 	&cmd_refresh_client_entry,
84 	&cmd_rename_session_entry,
85 	&cmd_rename_window_entry,
86 	&cmd_resize_pane_entry,
87 	&cmd_respawn_pane_entry,
88 	&cmd_respawn_window_entry,
89 	&cmd_rotate_window_entry,
90 	&cmd_run_shell_entry,
91 	&cmd_save_buffer_entry,
92 	&cmd_select_layout_entry,
93 	&cmd_select_pane_entry,
94 	&cmd_select_window_entry,
95 	&cmd_send_keys_entry,
96 	&cmd_send_prefix_entry,
97 	&cmd_server_info_entry,
98 	&cmd_set_buffer_entry,
99 	&cmd_set_environment_entry,
100 	&cmd_set_option_entry,
101 	&cmd_set_window_option_entry,
102 	&cmd_show_buffer_entry,
103 	&cmd_show_environment_entry,
104 	&cmd_show_messages_entry,
105 	&cmd_show_options_entry,
106 	&cmd_show_window_options_entry,
107 	&cmd_source_file_entry,
108 	&cmd_split_window_entry,
109 	&cmd_start_server_entry,
110 	&cmd_suspend_client_entry,
111 	&cmd_swap_pane_entry,
112 	&cmd_swap_window_entry,
113 	&cmd_switch_client_entry,
114 	&cmd_unbind_key_entry,
115 	&cmd_unlink_window_entry,
116 	NULL
117 };
118 
119 struct session	*cmd_choose_session_list(struct sessionslist *);
120 struct session	*cmd_choose_session(int);
121 struct client	*cmd_choose_client(struct clients *);
122 struct client	*cmd_lookup_client(const char *);
123 struct session	*cmd_lookup_session(const char *, int *);
124 struct winlink	*cmd_lookup_window(struct session *, const char *, int *);
125 int		 cmd_lookup_index(struct session *, const char *, int *);
126 struct window_pane *cmd_lookup_paneid(const char *);
127 struct winlink	*cmd_lookup_winlink_windowid(struct session *, const char *);
128 struct window	*cmd_lookup_windowid(const char *);
129 struct session	*cmd_window_session(struct cmd_ctx *,
130 		    struct window *, struct winlink **);
131 struct winlink	*cmd_find_window_offset(const char *, struct session *, int *);
132 int		 cmd_find_index_offset(const char *, struct session *, int *);
133 struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
134 
135 int
136 cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
137 {
138 	size_t	arglen;
139 	int	i;
140 
141 	*buf = '\0';
142 	for (i = 0; i < argc; i++) {
143 		if (strlcpy(buf, argv[i], len) >= len)
144 			return (-1);
145 		arglen = strlen(argv[i]) + 1;
146 		buf += arglen;
147 		len -= arglen;
148 	}
149 
150 	return (0);
151 }
152 
153 int
154 cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
155 {
156 	int	i;
157 	size_t	arglen;
158 
159 	if (argc == 0)
160 		return (0);
161 	*argv = xcalloc(argc, sizeof **argv);
162 
163 	buf[len - 1] = '\0';
164 	for (i = 0; i < argc; i++) {
165 		if (len == 0) {
166 			cmd_free_argv(argc, *argv);
167 			return (-1);
168 		}
169 
170 		arglen = strlen(buf) + 1;
171 		(*argv)[i] = xstrdup(buf);
172 		buf += arglen;
173 		len -= arglen;
174 	}
175 
176 	return (0);
177 }
178 
179 char **
180 cmd_copy_argv(int argc, char *const *argv)
181 {
182 	char	**new_argv;
183 	int	  i;
184 
185 	if (argc == 0)
186 		return (NULL);
187 	new_argv = xcalloc(argc, sizeof *new_argv);
188 	for (i = 0; i < argc; i++) {
189 		if (argv[i] != NULL)
190 			new_argv[i] = xstrdup(argv[i]);
191 	}
192 	return (new_argv);
193 }
194 
195 void
196 cmd_free_argv(int argc, char **argv)
197 {
198 	int	i;
199 
200 	if (argc == 0)
201 		return;
202 	for (i = 0; i < argc; i++)
203 		free(argv[i]);
204 	free(argv);
205 }
206 
207 struct cmd *
208 cmd_parse(int argc, char **argv, char **cause)
209 {
210 	const struct cmd_entry **entryp, *entry;
211 	struct cmd		*cmd;
212 	struct args		*args;
213 	char			 s[BUFSIZ];
214 	int			 ambiguous = 0;
215 
216 	*cause = NULL;
217 	if (argc == 0) {
218 		xasprintf(cause, "no command");
219 		return (NULL);
220 	}
221 
222 	entry = NULL;
223 	for (entryp = cmd_table; *entryp != NULL; entryp++) {
224 		if ((*entryp)->alias != NULL &&
225 		    strcmp((*entryp)->alias, argv[0]) == 0) {
226 			ambiguous = 0;
227 			entry = *entryp;
228 			break;
229 		}
230 
231 		if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
232 			continue;
233 		if (entry != NULL)
234 			ambiguous = 1;
235 		entry = *entryp;
236 
237 		/* Bail now if an exact match. */
238 		if (strcmp(entry->name, argv[0]) == 0)
239 			break;
240 	}
241 	if (ambiguous)
242 		goto ambiguous;
243 	if (entry == NULL) {
244 		xasprintf(cause, "unknown command: %s", argv[0]);
245 		return (NULL);
246 	}
247 
248 	args = args_parse(entry->args_template, argc, argv);
249 	if (args == NULL)
250 		goto usage;
251 	if (entry->args_lower != -1 && args->argc < entry->args_lower)
252 		goto usage;
253 	if (entry->args_upper != -1 && args->argc > entry->args_upper)
254 		goto usage;
255 	if (entry->check != NULL && entry->check(args) != 0)
256 		goto usage;
257 
258 	cmd = xmalloc(sizeof *cmd);
259 	cmd->entry = entry;
260 	cmd->args = args;
261 	return (cmd);
262 
263 ambiguous:
264 	*s = '\0';
265 	for (entryp = cmd_table; *entryp != NULL; entryp++) {
266 		if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
267 			continue;
268 		if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s)
269 			break;
270 		if (strlcat(s, ", ", sizeof s) >= sizeof s)
271 			break;
272 	}
273 	s[strlen(s) - 2] = '\0';
274 	xasprintf(cause, "ambiguous command: %s, could be: %s", argv[0], s);
275 	return (NULL);
276 
277 usage:
278 	if (args != NULL)
279 		args_free(args);
280 	xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
281 	return (NULL);
282 }
283 
284 enum cmd_retval
285 cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
286 {
287 	return (cmd->entry->exec(cmd, ctx));
288 }
289 
290 void
291 cmd_free(struct cmd *cmd)
292 {
293 	args_free(cmd->args);
294 	free(cmd);
295 }
296 
297 size_t
298 cmd_print(struct cmd *cmd, char *buf, size_t len)
299 {
300 	size_t	off, used;
301 
302 	off = xsnprintf(buf, len, "%s ", cmd->entry->name);
303 	if (off < len) {
304 		used = args_print(cmd->args, buf + off, len - off);
305 		if (used == 0)
306 			off--;
307 		else
308 			off += used;
309 		buf[off] = '\0';
310 	}
311 	return (off);
312 }
313 
314 /*
315  * Figure out the current session. Use: 1) the current session, if the command
316  * context has one; 2) the most recently used session containing the pty of the
317  * calling client, if any; 3) the session specified in the TMUX variable from
318  * the environment (as passed from the client); 4) the most recently used
319  * session from all sessions.
320  */
321 struct session *
322 cmd_current_session(struct cmd_ctx *ctx, int prefer_unattached)
323 {
324 	struct msg_command_data	*data = ctx->msgdata;
325 	struct client		*c = ctx->cmdclient;
326 	struct session		*s;
327 	struct sessionslist	 ss;
328 	struct winlink		*wl;
329 	struct window_pane	*wp;
330 	int			 found;
331 
332 	if (ctx->curclient != NULL && ctx->curclient->session != NULL)
333 		return (ctx->curclient->session);
334 
335 	/*
336 	 * If the name of the calling client's pty is know, build a list of the
337 	 * sessions that contain it and if any choose either the first or the
338 	 * newest.
339 	 */
340 	if (c != NULL && c->tty.path != NULL) {
341 		ARRAY_INIT(&ss);
342 		RB_FOREACH(s, sessions, &sessions) {
343 			found = 0;
344 			RB_FOREACH(wl, winlinks, &s->windows) {
345 				TAILQ_FOREACH(wp, &wl->window->panes, entry) {
346 					if (strcmp(wp->tty, c->tty.path) == 0) {
347 						found = 1;
348 						break;
349 					}
350 				}
351 				if (found)
352 					break;
353 			}
354 			if (found)
355 				ARRAY_ADD(&ss, s);
356 		}
357 
358 		s = cmd_choose_session_list(&ss);
359 		ARRAY_FREE(&ss);
360 		if (s != NULL)
361 			return (s);
362 	}
363 
364 	/* Use the session from the TMUX environment variable. */
365 	if (data != NULL && data->pid == getpid() && data->idx != -1) {
366 		s = session_find_by_index(data->idx);
367 		if (s != NULL)
368 			return (s);
369 	}
370 
371 	return (cmd_choose_session(prefer_unattached));
372 }
373 
374 /*
375  * Find the most recently used session, preferring unattached if the flag is
376  * set.
377  */
378 struct session *
379 cmd_choose_session(int prefer_unattached)
380 {
381 	struct session	*s, *sbest;
382 	struct timeval	*tv = NULL;
383 
384 	sbest = NULL;
385 	RB_FOREACH(s, sessions, &sessions) {
386 		if (tv == NULL || timercmp(&s->activity_time, tv, >) ||
387 		    (prefer_unattached &&
388 		    !(sbest->flags & SESSION_UNATTACHED) &&
389 		    (s->flags & SESSION_UNATTACHED))) {
390 			sbest = s;
391 			tv = &s->activity_time;
392 		}
393 	}
394 
395 	return (sbest);
396 }
397 
398 /* Find the most recently used session from a list. */
399 struct session *
400 cmd_choose_session_list(struct sessionslist *ss)
401 {
402 	struct session	*s, *sbest;
403 	struct timeval	*tv = NULL;
404 	u_int		 i;
405 
406 	sbest = NULL;
407 	for (i = 0; i < ARRAY_LENGTH(ss); i++) {
408 		if ((s = ARRAY_ITEM(ss, i)) == NULL)
409 			continue;
410 
411 		if (tv == NULL || timercmp(&s->activity_time, tv, >)) {
412 			sbest = s;
413 			tv = &s->activity_time;
414 		}
415 	}
416 
417 	return (sbest);
418 }
419 
420 /*
421  * Find the current client. First try the current client if set, then pick the
422  * most recently used of the clients attached to the current session if any,
423  * then of all clients.
424  */
425 struct client *
426 cmd_current_client(struct cmd_ctx *ctx)
427 {
428 	struct session		*s;
429 	struct client		*c;
430 	struct clients		 cc;
431 	u_int			 i;
432 
433 	if (ctx->curclient != NULL)
434 		return (ctx->curclient);
435 
436 	/*
437 	 * No current client set. Find the current session and return the
438 	 * newest of its clients.
439 	 */
440 	s = cmd_current_session(ctx, 0);
441 	if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
442 		ARRAY_INIT(&cc);
443 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
444 			if ((c = ARRAY_ITEM(&clients, i)) == NULL)
445 				continue;
446 			if (s == c->session)
447 				ARRAY_ADD(&cc, c);
448 		}
449 
450 		c = cmd_choose_client(&cc);
451 		ARRAY_FREE(&cc);
452 		if (c != NULL)
453 			return (c);
454 	}
455 
456 	return (cmd_choose_client(&clients));
457 }
458 
459 /* Choose the most recently used client from a list. */
460 struct client *
461 cmd_choose_client(struct clients *cc)
462 {
463 	struct client	*c, *cbest;
464 	struct timeval	*tv = NULL;
465 	u_int		 i;
466 
467 	cbest = NULL;
468 	for (i = 0; i < ARRAY_LENGTH(cc); i++) {
469 		if ((c = ARRAY_ITEM(cc, i)) == NULL)
470 			continue;
471 		if (c->session == NULL)
472 			continue;
473 
474 		if (tv == NULL || timercmp(&c->activity_time, tv, >)) {
475 			cbest = c;
476 			tv = &c->activity_time;
477 		}
478 	}
479 
480 	return (cbest);
481 }
482 
483 /* Find the target client or report an error and return NULL. */
484 struct client *
485 cmd_find_client(struct cmd_ctx *ctx, const char *arg)
486 {
487 	struct client	*c;
488 	char		*tmparg;
489 	size_t		 arglen;
490 
491 	/* A NULL argument means the current client. */
492 	if (arg == NULL)
493 		return (cmd_current_client(ctx));
494 	tmparg = xstrdup(arg);
495 
496 	/* Trim a single trailing colon if any. */
497 	arglen = strlen(tmparg);
498 	if (arglen != 0 && tmparg[arglen - 1] == ':')
499 		tmparg[arglen - 1] = '\0';
500 
501 	/* Find the client, if any. */
502 	c = cmd_lookup_client(tmparg);
503 
504 	/* If no client found, report an error. */
505 	if (c == NULL)
506 		ctx->error(ctx, "client not found: %s", tmparg);
507 
508 	free(tmparg);
509 	return (c);
510 }
511 
512 /*
513  * Lookup a client by device path. Either of a full match and a match without a
514  * leading _PATH_DEV ("/dev/") is accepted.
515  */
516 struct client *
517 cmd_lookup_client(const char *name)
518 {
519 	struct client	*c;
520 	const char	*path;
521 	u_int		 i;
522 
523 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
524 		c = ARRAY_ITEM(&clients, i);
525 		if (c == NULL || c->session == NULL)
526 			continue;
527 		path = c->tty.path;
528 
529 		/* Check for exact matches. */
530 		if (strcmp(name, path) == 0)
531 			return (c);
532 
533 		/* Check without leading /dev if present. */
534 		if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
535 			continue;
536 		if (strcmp(name, path + (sizeof _PATH_DEV) - 1) == 0)
537 			return (c);
538 	}
539 
540 	return (NULL);
541 }
542 
543 /* Lookup a session by name. If no session is found, NULL is returned. */
544 struct session *
545 cmd_lookup_session(const char *name, int *ambiguous)
546 {
547 	struct session	*s, *sfound;
548 
549 	*ambiguous = 0;
550 
551 	/*
552 	 * Look for matches. First look for exact matches - session names must
553 	 * be unique so an exact match can't be ambigious and can just be
554 	 * returned.
555 	 */
556 	if ((s = session_find(name)) != NULL)
557 		return (s);
558 
559 	/*
560 	 * Otherwise look for partial matches, returning early if it is found to
561 	 * be ambiguous.
562 	 */
563 	sfound = NULL;
564 	RB_FOREACH(s, sessions, &sessions) {
565 		if (strncmp(name, s->name, strlen(name)) == 0 ||
566 		    fnmatch(name, s->name, 0) == 0) {
567 			if (sfound != NULL) {
568 				*ambiguous = 1;
569 				return (NULL);
570 			}
571 			sfound = s;
572 		}
573 	}
574 	return (sfound);
575 }
576 
577 /*
578  * Lookup a window or return -1 if not found or ambigious. First try as an
579  * index and if invalid, use fnmatch or leading prefix. Return NULL but fill in
580  * idx if the window index is a valid number but there is no window with that
581  * index.
582  */
583 struct winlink *
584 cmd_lookup_window(struct session *s, const char *name, int *ambiguous)
585 {
586 	struct winlink	*wl, *wlfound;
587 	const char	*errstr;
588 	u_int		 idx;
589 
590 	*ambiguous = 0;
591 
592 	/* Try as a window id. */
593 	if ((wl = cmd_lookup_winlink_windowid(s, name)) != NULL)
594 	    return (wl);
595 
596 	/* First see if this is a valid window index in this session. */
597 	idx = strtonum(name, 0, INT_MAX, &errstr);
598 	if (errstr == NULL) {
599 		if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL)
600 			return (wl);
601 	}
602 
603 	/* Look for exact matches, error if more than one. */
604 	wlfound = NULL;
605 	RB_FOREACH(wl, winlinks, &s->windows) {
606 		if (strcmp(name, wl->window->name) == 0) {
607 			if (wlfound != NULL) {
608 				*ambiguous = 1;
609 				return (NULL);
610 			}
611 			wlfound = wl;
612 		}
613 	}
614 	if (wlfound != NULL)
615 		return (wlfound);
616 
617 	/* Now look for pattern matches, again error if multiple. */
618 	wlfound = NULL;
619 	RB_FOREACH(wl, winlinks, &s->windows) {
620 		if (strncmp(name, wl->window->name, strlen(name)) == 0 ||
621 		    fnmatch(name, wl->window->name, 0) == 0) {
622 			if (wlfound != NULL) {
623 				*ambiguous = 1;
624 				return (NULL);
625 			}
626 			wlfound = wl;
627 		}
628 	}
629 	if (wlfound != NULL)
630 		return (wlfound);
631 
632 	return (NULL);
633 }
634 
635 /*
636  * Find a window index - if the window doesn't exist, check if it is a
637  * potential index and return it anyway.
638  */
639 int
640 cmd_lookup_index(struct session *s, const char *name, int *ambiguous)
641 {
642 	struct winlink	*wl;
643 	const char	*errstr;
644 	u_int		 idx;
645 
646 	if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL)
647 		return (wl->idx);
648 	if (*ambiguous)
649 		return (-1);
650 
651 	idx = strtonum(name, 0, INT_MAX, &errstr);
652 	if (errstr == NULL)
653 		return (idx);
654 
655 	return (-1);
656 }
657 
658 /* Lookup pane id. An initial % means a pane id. */
659 struct window_pane *
660 cmd_lookup_paneid(const char *arg)
661 {
662 	const char	*errstr;
663 	u_int		 paneid;
664 
665 	if (*arg != '%')
666 		return (NULL);
667 
668 	paneid = strtonum(arg + 1, 0, UINT_MAX, &errstr);
669 	if (errstr != NULL)
670 		return (NULL);
671 	return (window_pane_find_by_id(paneid));
672 }
673 
674 /* Lookup window id in a session. An initial @ means a window id. */
675 struct winlink *
676 cmd_lookup_winlink_windowid(struct session *s, const char *arg)
677 {
678 	const char	*errstr;
679 	u_int		 windowid;
680 
681 	if (*arg != '@')
682 		return (NULL);
683 
684 	windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr);
685 	if (errstr != NULL)
686 		return (NULL);
687 	return (winlink_find_by_window_id(&s->windows, windowid));
688 }
689 
690 /* Lookup window id. An initial @ means a window id. */
691 struct window *
692 cmd_lookup_windowid(const char *arg)
693 {
694 	const char	*errstr;
695 	u_int		 windowid;
696 
697 	if (*arg != '@')
698 		return (NULL);
699 
700 	windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr);
701 	if (errstr != NULL)
702 		return (NULL);
703 	return (window_find_by_id(windowid));
704 }
705 
706 /* Find session and winlink for window. */
707 struct session *
708 cmd_window_session(struct cmd_ctx *ctx, struct window *w, struct winlink **wlp)
709 {
710 	struct session		*s;
711 	struct sessionslist	 ss;
712 	struct winlink		*wl;
713 
714 	/* If this window is in the current session, return that winlink. */
715 	s = cmd_current_session(ctx, 0);
716 	if (s != NULL) {
717 		wl = winlink_find_by_window(&s->windows, w);
718 		if (wl != NULL) {
719 			if (wlp != NULL)
720 				*wlp = wl;
721 			return (s);
722 		}
723 	}
724 
725 	/* Otherwise choose from all sessions with this window. */
726 	ARRAY_INIT(&ss);
727 	RB_FOREACH(s, sessions, &sessions) {
728 		if (winlink_find_by_window(&s->windows, w) != NULL)
729 			ARRAY_ADD(&ss, s);
730 	}
731 	s = cmd_choose_session_list(&ss);
732 	ARRAY_FREE(&ss);
733 	if (wlp != NULL)
734 		*wlp = winlink_find_by_window(&s->windows, w);
735 	return (s);
736 }
737 
738 /* Find the target session or report an error and return NULL. */
739 struct session *
740 cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
741 {
742 	struct session		*s;
743 	struct window_pane	*wp;
744 	struct window		*w;
745 	struct client		*c;
746 	char			*tmparg;
747 	size_t			 arglen;
748 	int			 ambiguous;
749 
750 	/* A NULL argument means the current session. */
751 	if (arg == NULL)
752 		return (cmd_current_session(ctx, prefer_unattached));
753 
754 	/* Lookup as pane id or window id. */
755 	if ((wp = cmd_lookup_paneid(arg)) != NULL)
756 		return (cmd_window_session(ctx, wp->window, NULL));
757 	if ((w = cmd_lookup_windowid(arg)) != NULL)
758 		return (cmd_window_session(ctx, w, NULL));
759 
760 	/* Trim a single trailing colon if any. */
761 	tmparg = xstrdup(arg);
762 	arglen = strlen(tmparg);
763 	if (arglen != 0 && tmparg[arglen - 1] == ':')
764 		tmparg[arglen - 1] = '\0';
765 
766 	/* An empty session name is the current session. */
767 	if (*tmparg == '\0') {
768 		free(tmparg);
769 		return (cmd_current_session(ctx, prefer_unattached));
770 	}
771 
772 	/* Find the session, if any. */
773 	s = cmd_lookup_session(tmparg, &ambiguous);
774 
775 	/* If it doesn't, try to match it as a client. */
776 	if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL)
777 		s = c->session;
778 
779 	/* If no session found, report an error. */
780 	if (s == NULL) {
781 		if (ambiguous)
782 			ctx->error(ctx, "more than one session: %s", tmparg);
783 		else
784 			ctx->error(ctx, "session not found: %s", tmparg);
785 	}
786 
787 	free(tmparg);
788 	return (s);
789 }
790 
791 /* Find the target session and window or report an error and return NULL. */
792 struct winlink *
793 cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
794 {
795 	struct session		*s;
796 	struct winlink		*wl;
797 	struct window_pane	*wp;
798 	const char		*winptr;
799 	char			*sessptr = NULL;
800 	int			 ambiguous = 0;
801 
802 	/*
803 	 * Find the current session. There must always be a current session, if
804 	 * it can't be found, report an error.
805 	 */
806 	if ((s = cmd_current_session(ctx, 0)) == NULL) {
807 		ctx->error(ctx, "can't establish current session");
808 		return (NULL);
809 	}
810 
811 	/* A NULL argument means the current session and window. */
812 	if (arg == NULL) {
813 		if (sp != NULL)
814 			*sp = s;
815 		return (s->curw);
816 	}
817 
818 	/* Lookup as pane id. */
819 	if ((wp = cmd_lookup_paneid(arg)) != NULL) {
820 		s = cmd_window_session(ctx, wp->window, &wl);
821 		if (sp != NULL)
822 			*sp = s;
823 		return (wl);
824 	}
825 
826 	/* Time to look at the argument. If it is empty, that is an error. */
827 	if (*arg == '\0')
828 		goto not_found;
829 
830 	/* Find the separating colon and split into window and session. */
831 	winptr = strchr(arg, ':');
832 	if (winptr == NULL)
833 		goto no_colon;
834 	winptr++;	/* skip : */
835 	sessptr = xstrdup(arg);
836 	*strchr(sessptr, ':') = '\0';
837 
838 	/* Try to lookup the session if present. */
839 	if (*sessptr != '\0') {
840 		if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
841 			goto no_session;
842 	}
843 	if (sp != NULL)
844 		*sp = s;
845 
846 	/*
847 	 * Then work out the window. An empty string is the current window,
848 	 * otherwise try special cases then to look it up in the session.
849 	 */
850 	if (*winptr == '\0')
851 		wl = s->curw;
852 	else if (winptr[0] == '!' && winptr[1] == '\0')
853 		wl = TAILQ_FIRST(&s->lastw);
854 	else if (winptr[0] == '+' || winptr[0] == '-')
855 		wl = cmd_find_window_offset(winptr, s, &ambiguous);
856 	else
857 		wl = cmd_lookup_window(s, winptr, &ambiguous);
858 	if (wl == NULL)
859 		goto not_found;
860 
861 	if (sessptr != NULL)
862 		free(sessptr);
863 	return (wl);
864 
865 no_colon:
866 	/*
867 	 * No colon in the string, first try special cases, then as a window
868 	 * and lastly as a session.
869 	 */
870 	if (arg[0] == '!' && arg[1] == '\0') {
871 		if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
872 			goto not_found;
873 	} else if (arg[0] == '+' || arg[0] == '-') {
874 		if ((wl = cmd_find_window_offset(arg, s, &ambiguous)) == NULL)
875 			goto lookup_session;
876 	} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL)
877 		goto lookup_session;
878 
879 	if (sp != NULL)
880 		*sp = s;
881 
882 	return (wl);
883 
884 lookup_session:
885 	if (ambiguous)
886 		goto not_found;
887 	if (*arg != '\0' && (s = cmd_lookup_session(arg, &ambiguous)) == NULL)
888 		goto no_session;
889 
890 	if (sp != NULL)
891 		*sp = s;
892 
893 	return (s->curw);
894 
895 no_session:
896 	if (ambiguous)
897 		ctx->error(ctx, "multiple sessions: %s", arg);
898 	else
899 		ctx->error(ctx, "session not found: %s", arg);
900 	free(sessptr);
901 	return (NULL);
902 
903 not_found:
904 	if (ambiguous)
905 		ctx->error(ctx, "multiple windows: %s", arg);
906 	else
907 		ctx->error(ctx, "window not found: %s", arg);
908 	free(sessptr);
909 	return (NULL);
910 }
911 
912 struct winlink *
913 cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
914 {
915 	struct winlink	*wl;
916 	int		 offset = 1;
917 
918 	if (winptr[1] != '\0')
919 		offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
920 	if (offset == 0)
921 		wl = cmd_lookup_window(s, winptr, ambiguous);
922 	else {
923 		if (winptr[0] == '+')
924 			wl = winlink_next_by_number(s->curw, s, offset);
925 		else
926 			wl = winlink_previous_by_number(s->curw, s, offset);
927 	}
928 
929 	return (wl);
930 }
931 
932 /*
933  * Find the target session and window index, whether or not it exists in the
934  * session. Return -2 on error or -1 if no window index is specified. This is
935  * used when parsing an argument for a window target that may not exist (for
936  * example if it is going to be created).
937  */
938 int
939 cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
940 {
941 	struct session	*s;
942 	struct winlink	*wl;
943 	const char	*winptr;
944 	char		*sessptr = NULL;
945 	int		 idx, ambiguous = 0;
946 
947 	/*
948 	 * Find the current session. There must always be a current session, if
949 	 * it can't be found, report an error.
950 	 */
951 	if ((s = cmd_current_session(ctx, 0)) == NULL) {
952 		ctx->error(ctx, "can't establish current session");
953 		return (-2);
954 	}
955 
956 	/* A NULL argument means the current session and "no window" (-1). */
957 	if (arg == NULL) {
958 		if (sp != NULL)
959 			*sp = s;
960 		return (-1);
961 	}
962 
963 	/* Time to look at the argument. If it is empty, that is an error. */
964 	if (*arg == '\0')
965 		goto not_found;
966 
967 	/* Find the separating colon. If none, assume the current session. */
968 	winptr = strchr(arg, ':');
969 	if (winptr == NULL)
970 		goto no_colon;
971 	winptr++;	/* skip : */
972 	sessptr = xstrdup(arg);
973 	*strchr(sessptr, ':') = '\0';
974 
975 	/* Try to lookup the session if present. */
976 	if (sessptr != NULL && *sessptr != '\0') {
977 		if ((s = cmd_lookup_session(sessptr, &ambiguous)) == NULL)
978 			goto no_session;
979 	}
980 	if (sp != NULL)
981 		*sp = s;
982 
983 	/*
984 	 * Then work out the window. An empty string is a new window otherwise
985 	 * try to look it up in the session.
986 	 */
987 	if (*winptr == '\0')
988 		idx = -1;
989 	else if (winptr[0] == '!' && winptr[1] == '\0') {
990 		if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
991 			goto not_found;
992 		idx = wl->idx;
993 	} else if (winptr[0] == '+' || winptr[0] == '-') {
994 		if ((idx = cmd_find_index_offset(winptr, s, &ambiguous)) < 0)
995 			goto invalid_index;
996 	} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1)
997 		goto invalid_index;
998 
999 	free(sessptr);
1000 	return (idx);
1001 
1002 no_colon:
1003 	/*
1004 	 * No colon in the string, first try special cases, then as a window
1005 	 * and lastly as a session.
1006 	 */
1007 	if (arg[0] == '!' && arg[1] == '\0') {
1008 		if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
1009 			goto not_found;
1010 		idx = wl->idx;
1011 	} else if (arg[0] == '+' || arg[0] == '-') {
1012 		if ((idx = cmd_find_index_offset(arg, s, &ambiguous)) < 0)
1013 			goto lookup_session;
1014 	} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1)
1015 		goto lookup_session;
1016 
1017 	if (sp != NULL)
1018 		*sp = s;
1019 
1020 	return (idx);
1021 
1022 lookup_session:
1023 	if (ambiguous)
1024 		goto not_found;
1025 	if (*arg != '\0' && (s = cmd_lookup_session(arg, &ambiguous)) == NULL)
1026 		goto no_session;
1027 
1028 	if (sp != NULL)
1029 		*sp = s;
1030 
1031 	return (-1);
1032 
1033 no_session:
1034 	if (ambiguous)
1035 		ctx->error(ctx, "multiple sessions: %s", arg);
1036 	else
1037 		ctx->error(ctx, "session not found: %s", arg);
1038 	free(sessptr);
1039 	return (-2);
1040 
1041 invalid_index:
1042 	if (ambiguous)
1043 		goto not_found;
1044 	ctx->error(ctx, "invalid index: %s", arg);
1045 
1046 	free(sessptr);
1047 	return (-2);
1048 
1049 not_found:
1050 	if (ambiguous)
1051 		ctx->error(ctx, "multiple windows: %s", arg);
1052 	else
1053 		ctx->error(ctx, "window not found: %s", arg);
1054 	free(sessptr);
1055 	return (-2);
1056 }
1057 
1058 int
1059 cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
1060 {
1061 	int	idx, offset = 1;
1062 
1063 	if (winptr[1] != '\0')
1064 		offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
1065 	if (offset == 0)
1066 		idx = cmd_lookup_index(s, winptr, ambiguous);
1067 	else {
1068 		if (winptr[0] == '+') {
1069 			if (s->curw->idx == INT_MAX)
1070 				idx = cmd_lookup_index(s, winptr, ambiguous);
1071 			else
1072 				idx = s->curw->idx + offset;
1073 		} else {
1074 			if (s->curw->idx == 0)
1075 				idx = cmd_lookup_index(s, winptr, ambiguous);
1076 			else
1077 				idx = s->curw->idx - offset;
1078 		}
1079 	}
1080 
1081 	return (idx);
1082 }
1083 
1084 /*
1085  * Find the target session, window and pane number or report an error and
1086  * return NULL. The pane number is separated from the session:window by a .,
1087  * such as mysession:mywindow.0.
1088  */
1089 struct winlink *
1090 cmd_find_pane(struct cmd_ctx *ctx,
1091     const char *arg, struct session **sp, struct window_pane **wpp)
1092 {
1093 	struct session	*s;
1094 	struct winlink	*wl;
1095 	const char	*period, *errstr;
1096 	char		*winptr, *paneptr;
1097 	u_int		 idx;
1098 
1099 	/* Get the current session. */
1100 	if ((s = cmd_current_session(ctx, 0)) == NULL) {
1101 		ctx->error(ctx, "can't establish current session");
1102 		return (NULL);
1103 	}
1104 	if (sp != NULL)
1105 		*sp = s;
1106 
1107 	/* A NULL argument means the current session, window and pane. */
1108 	if (arg == NULL) {
1109 		*wpp = s->curw->window->active;
1110 		return (s->curw);
1111 	}
1112 
1113 	/* Lookup as pane id. */
1114 	if ((*wpp = cmd_lookup_paneid(arg)) != NULL) {
1115 		s = cmd_window_session(ctx, (*wpp)->window, &wl);
1116 		if (sp != NULL)
1117 			*sp = s;
1118 		return (wl);
1119 	}
1120 
1121 	/* Look for a separating period. */
1122 	if ((period = strrchr(arg, '.')) == NULL)
1123 		goto no_period;
1124 
1125 	/* Pull out the window part and parse it. */
1126 	winptr = xstrdup(arg);
1127 	winptr[period - arg] = '\0';
1128 	if (*winptr == '\0')
1129 		wl = s->curw;
1130 	else if ((wl = cmd_find_window(ctx, winptr, sp)) == NULL)
1131 		goto error;
1132 
1133 	/* Find the pane section and look it up. */
1134 	paneptr = winptr + (period - arg) + 1;
1135 	if (*paneptr == '\0')
1136 		*wpp = wl->window->active;
1137 	else if (paneptr[0] == '+' || paneptr[0] == '-')
1138 		*wpp = cmd_find_pane_offset(paneptr, wl);
1139 	else {
1140 		idx = strtonum(paneptr, 0, INT_MAX, &errstr);
1141 		if (errstr != NULL)
1142 			goto lookup_string;
1143 		*wpp = window_pane_at_index(wl->window, idx);
1144 		if (*wpp == NULL)
1145 			goto lookup_string;
1146 	}
1147 
1148 	free(winptr);
1149 	return (wl);
1150 
1151 lookup_string:
1152 	/* Try pane string description. */
1153 	if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) {
1154 		ctx->error(ctx, "can't find pane: %s", paneptr);
1155 		goto error;
1156 	}
1157 
1158 	free(winptr);
1159 	return (wl);
1160 
1161 no_period:
1162 	/* Try as a pane number alone. */
1163 	idx = strtonum(arg, 0, INT_MAX, &errstr);
1164 	if (errstr != NULL)
1165 		goto lookup_window;
1166 
1167 	/* Try index in the current session and window. */
1168 	if ((*wpp = window_pane_at_index(s->curw->window, idx)) == NULL)
1169 		goto lookup_window;
1170 
1171 	return (s->curw);
1172 
1173 lookup_window:
1174 	/* Try pane string description. */
1175 	if ((*wpp = window_find_string(s->curw->window, arg)) != NULL)
1176 		return (s->curw);
1177 
1178 	/* Try as a window and use the active pane. */
1179 	if ((wl = cmd_find_window(ctx, arg, sp)) != NULL)
1180 		*wpp = wl->window->active;
1181 	return (wl);
1182 
1183 error:
1184 	free(winptr);
1185 	return (NULL);
1186 }
1187 
1188 struct window_pane *
1189 cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
1190 {
1191 	struct window		*w = wl->window;
1192 	struct window_pane	*wp = w->active;
1193 	u_int			 offset = 1;
1194 
1195 	if (paneptr[1] != '\0')
1196 		offset = strtonum(paneptr + 1, 1, INT_MAX, NULL);
1197 	if (offset > 0) {
1198 		if (paneptr[0] == '+')
1199 			wp = window_pane_next_by_number(w, wp, offset);
1200 		else
1201 			wp = window_pane_previous_by_number(w, wp, offset);
1202 	}
1203 
1204 	return (wp);
1205 }
1206 
1207 /* Replace the first %% or %idx in template by s. */
1208 char *
1209 cmd_template_replace(char *template, const char *s, int idx)
1210 {
1211 	char	 ch;
1212 	char	*buf, *ptr;
1213 	int	 replaced;
1214 	size_t	 len;
1215 
1216 	if (strstr(template, "%") == NULL)
1217 		return (xstrdup(template));
1218 
1219 	buf = xmalloc(1);
1220 	*buf = '\0';
1221 	len = 0;
1222 	replaced = 0;
1223 
1224 	ptr = template;
1225 	while (*ptr != '\0') {
1226 		switch (ch = *ptr++) {
1227 		case '%':
1228 			if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
1229 				if (*ptr != '%' || replaced)
1230 					break;
1231 				replaced = 1;
1232 			}
1233 			ptr++;
1234 
1235 			len += strlen(s);
1236 			buf = xrealloc(buf, 1, len + 1);
1237 			strlcat(buf, s, len + 1);
1238 			continue;
1239 		}
1240 		buf = xrealloc(buf, 1, len + 2);
1241 		buf[len++] = ch;
1242 		buf[len] = '\0';
1243 	}
1244 
1245 	return (buf);
1246 }
1247 
1248 /*
1249  * Return the default path for a new pane, using the given path or the
1250  * default-path option if it is NULL. Several special values are accepted: the
1251  * empty string or relative path for the current pane's working directory, ~
1252  * for the user's home, - for the session working directory, . for the tmux
1253  * server's working directory. The default on failure is the session's working
1254  * directory.
1255  */
1256 const char *
1257 cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd)
1258 {
1259 	struct session		*s;
1260 	struct environ_entry	*envent;
1261 	const char		*root;
1262 	char			 tmp[MAXPATHLEN];
1263 	struct passwd		*pw;
1264 	int			 n;
1265 	size_t			 skip;
1266 	static char		 path[MAXPATHLEN];
1267 
1268 	if ((s = cmd_current_session(ctx, 0)) == NULL)
1269 		return (NULL);
1270 
1271 	if (cwd == NULL)
1272 		cwd = options_get_string(&s->options, "default-path");
1273 
1274 	skip = 1;
1275 	if (strcmp(cwd, "$HOME") == 0 || strncmp(cwd, "$HOME/", 6) == 0) {
1276 		/* User's home directory - $HOME. */
1277 		skip = 5;
1278 		goto find_home;
1279 	} else if (cwd[0] == '~' && (cwd[1] == '\0' || cwd[1] == '/')) {
1280 		/* User's home directory - ~. */
1281 		goto find_home;
1282 	} else if (cwd[0] == '-' && (cwd[1] == '\0' || cwd[1] == '/')) {
1283 		/* Session working directory. */
1284 		root = s->cwd;
1285 		goto complete_path;
1286 	} else if (cwd[0] == '.' && (cwd[1] == '\0' || cwd[1] == '/')) {
1287 		/* Server working directory. */
1288 		if (getcwd(tmp, sizeof tmp) != NULL) {
1289 			root = tmp;
1290 			goto complete_path;
1291 		}
1292 		return (s->cwd);
1293 	} else if (*cwd == '/') {
1294 		/* Absolute path. */
1295 		return (cwd);
1296 	} else {
1297 		/* Empty or relative path. */
1298 		if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
1299 			root = ctx->cmdclient->cwd;
1300 		else if (ctx->curclient != NULL && s->curw != NULL)
1301 			root = get_proc_cwd(s->curw->window->active->pid);
1302 		else
1303 			return (s->cwd);
1304 		skip = 0;
1305 		if (root != NULL)
1306 			goto complete_path;
1307 	}
1308 
1309 	return (s->cwd);
1310 
1311 find_home:
1312 	envent = environ_find(&global_environ, "HOME");
1313 	if (envent != NULL && *envent->value != '\0')
1314 		root = envent->value;
1315 	else if ((pw = getpwuid(getuid())) != NULL)
1316 		root = pw->pw_dir;
1317 	else
1318 		return (s->cwd);
1319 
1320 complete_path:
1321 	if (root[skip] == '\0') {
1322 		strlcpy(path, root, sizeof path);
1323 		return (path);
1324 	}
1325 	n = snprintf(path, sizeof path, "%s/%s", root, cwd + skip);
1326 	if (n > 0 && (size_t)n < sizeof path)
1327 		return (path);
1328 	return (s->cwd);
1329 }
1330