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