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