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

tmux.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/utsname.h>
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <langinfo.h>
26 #include <locale.h>
27 #include <pwd.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 
34 #include "tmux.h"
35 
36 struct options *global_options; /* server options */
37 struct options *global_s_options; /* session options */
38 struct options *global_w_options; /* window options */
40 
41 struct timeval start_time;
42 const char *socket_path;
43 int ptm_fd = -1;
44 const char *shell_command;
45 
46 static __dead void usage(void);
47 static char *make_label(const char *, char **);
48 
49 static int areshell(const char *);
50 static const char *getshell(void);
51 
52 static __dead void
53 usage(void)
54 {
55  fprintf(stderr,
56  "usage: %s [-2CDlNuvV] [-c shell-command] [-f file] [-L socket-name]\n"
57  " [-S socket-path] [-T features] [command [flags]]\n",
58  getprogname());
59  exit(1);
60 }
61 
62 static const char *
63 getshell(void)
64 {
65  struct passwd *pw;
66  const char *shell;
67 
68  shell = getenv("SHELL");
69  if (checkshell(shell))
70  return (shell);
71 
72  pw = getpwuid(getuid());
73  if (pw != NULL && checkshell(pw->pw_shell))
74  return (pw->pw_shell);
75 
76  return (_PATH_BSHELL);
77 }
78 
79 int
80 checkshell(const char *shell)
81 {
82  if (shell == NULL || *shell != '/')
83  return (0);
84  if (areshell(shell))
85  return (0);
86  if (access(shell, X_OK) != 0)
87  return (0);
88  return (1);
89 }
90 
91 static int
92 areshell(const char *shell)
93 {
94  const char *progname, *ptr;
95 
96  if ((ptr = strrchr(shell, '/')) != NULL)
97  ptr++;
98  else
99  ptr = shell;
100  progname = getprogname();
101  if (*progname == '-')
102  progname++;
103  if (strcmp(ptr, progname) == 0)
104  return (1);
105  return (0);
106 }
107 
108 static char *
109 expand_path(const char *path, const char *home)
110 {
111  char *expanded, *name;
112  const char *end;
113  struct environ_entry *value;
114 
115  if (strncmp(path, "~/", 2) == 0) {
116  if (home == NULL)
117  return (NULL);
118  xasprintf(&expanded, "%s%s", home, path + 1);
119  return (expanded);
120  }
121 
122  if (*path == '$') {
123  end = strchr(path, '/');
124  if (end == NULL)
125  name = xstrdup(path + 1);
126  else
127  name = xstrndup(path + 1, end - path - 1);
129  free(name);
130  if (value == NULL)
131  return (NULL);
132  if (end == NULL)
133  end = "";
134  xasprintf(&expanded, "%s%s", value->value, end);
135  return (expanded);
136  }
137 
138  return (xstrdup(path));
139 }
140 
141 static void
142 expand_paths(const char *s, char ***paths, u_int *n, int ignore_errors)
143 {
144  const char *home = find_home();
145  char *copy, *next, *tmp, resolved[PATH_MAX], *expanded;
146  char *path;
147  u_int i;
148 
149  *paths = NULL;
150  *n = 0;
151 
152  copy = tmp = xstrdup(s);
153  while ((next = strsep(&tmp, ":")) != NULL) {
154  expanded = expand_path(next, home);
155  if (expanded == NULL) {
156  log_debug("%s: invalid path: %s", __func__, next);
157  continue;
158  }
159  if (realpath(expanded, resolved) == NULL) {
160  log_debug("%s: realpath(\"%s\") failed: %s", __func__,
161  expanded, strerror(errno));
162  if (ignore_errors) {
163  free(expanded);
164  continue;
165  }
166  path = expanded;
167  } else {
168  path = xstrdup(resolved);
169  free(expanded);
170  }
171  for (i = 0; i < *n; i++) {
172  if (strcmp(path, (*paths)[i]) == 0)
173  break;
174  }
175  if (i != *n) {
176  log_debug("%s: duplicate path: %s", __func__, path);
177  free(path);
178  continue;
179  }
180  *paths = xreallocarray(*paths, (*n) + 1, sizeof *paths);
181  (*paths)[(*n)++] = path;
182  }
183  free(copy);
184 }
185 
186 static char *
187 make_label(const char *label, char **cause)
188 {
189  char **paths, *path, *base;
190  u_int i, n;
191  struct stat sb;
192  uid_t uid;
193 
194  *cause = NULL;
195  if (label == NULL)
196  label = "default";
197  uid = getuid();
198 
199  expand_paths(TMUX_SOCK, &paths, &n, 1);
200  if (n == 0) {
201  xasprintf(cause, "no suitable socket path");
202  return (NULL);
203  }
204  path = paths[0]; /* can only have one socket! */
205  for (i = 1; i < n; i++)
206  free(paths[i]);
207  free(paths);
208 
209  xasprintf(&base, "%s/tmux-%ld", path, (long)uid);
210  if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
211  goto fail;
212  if (lstat(base, &sb) != 0)
213  goto fail;
214  if (!S_ISDIR(sb.st_mode)) {
215  errno = ENOTDIR;
216  goto fail;
217  }
218  if (sb.st_uid != uid || (sb.st_mode & S_IRWXO) != 0) {
219  errno = EACCES;
220  goto fail;
221  }
222  xasprintf(&path, "%s/%s", base, label);
223  free(base);
224  return (path);
225 
226 fail:
227  xasprintf(cause, "error creating %s (%s)", base, strerror(errno));
228  free(base);
229  return (NULL);
230 }
231 
232 void
233 setblocking(int fd, int state)
234 {
235  int mode;
236 
237  if ((mode = fcntl(fd, F_GETFL)) != -1) {
238  if (!state)
239  mode |= O_NONBLOCK;
240  else
241  mode &= ~~O_NONBLOCK;
242  fcntl(fd, F_SETFL, mode);
243  }
244 }
245 
246 uint64_t
248 {
249  struct timespec ts;
250 
251  /*
252  * We want a timestamp in milliseconds suitable for time measurement,
253  * so prefer the monotonic clock.
254  */
255  if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
257  return ((ts.tv_sec * 1000ULL) + (ts.tv_nsec / 1000000ULL));
258 }
259 
260 const char *
261 sig2name(int signo)
262 {
263  static char s[11];
264 
265 #ifdef HAVE_SYS_SIGNAME
266  if (signo > 0 && signo < NSIG)
267  return (sys_signame[signo]);
268 #endif
269  xsnprintf(s, sizeof s, "%d", signo);
270  return (s);
271 }
272 
273 const char *
274 find_cwd(void)
275 {
276  char resolved1[PATH_MAX], resolved2[PATH_MAX];
277  static char cwd[PATH_MAX];
278  const char *pwd;
279 
280  if (getcwd(cwd, sizeof cwd) == NULL)
281  return (NULL);
282  if ((pwd = getenv("PWD")) == NULL || *pwd == '\0')
283  return (cwd);
284 
285  /*
286  * We want to use PWD so that symbolic links are maintained,
287  * but only if it matches the actual working directory.
288  */
289  if (realpath(pwd, resolved1) == NULL)
290  return (cwd);
291  if (realpath(cwd, resolved2) == NULL)
292  return (cwd);
293  if (strcmp(resolved1, resolved2) != 0)
294  return (cwd);
295  return (pwd);
296 }
297 
298 const char *
300 {
301  struct passwd *pw;
302  static const char *home;
303 
304  if (home != NULL)
305  return (home);
306 
307  home = getenv("HOME");
308  if (home == NULL || *home == '\0') {
309  pw = getpwuid(getuid());
310  if (pw != NULL)
311  home = pw->pw_dir;
312  else
313  home = NULL;
314  }
315 
316  return (home);
317 }
318 
319 const char *
321 {
322  return TMUX_VERSION;
323 }
324 
325 int
326 main(int argc, char **argv)
327 {
328  char *path = NULL, *label = NULL;
329  char *cause, **var;
330  const char *s, *cwd;
331  int opt, keys, feat = 0, fflag = 0;
332  uint64_t flags = 0;
333  const struct options_table_entry *oe;
334  u_int i;
335 
336  if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL &&
337  setlocale(LC_CTYPE, "C.UTF-8") == NULL) {
338  if (setlocale(LC_CTYPE, "") == NULL)
339  errx(1, "invalid LC_ALL, LC_CTYPE or LANG");
340  s = nl_langinfo(CODESET);
341  if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0)
342  errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s);
343  }
344 
345  setlocale(LC_TIME, "");
346  tzset();
347 
348  if (**argv == '-')
350 
352  for (var = environ; *var != NULL; var++)
353  environ_put(global_environ, *var, 0);
354  if ((cwd = find_cwd()) != NULL)
355  environ_set(global_environ, "PWD", 0, "%s", cwd);
357 
358  while ((opt = getopt(argc, argv, "2c:CDdf:lL:NqS:T:uUvV")) != -1) {
359  switch (opt) {
360  case '2':
361  tty_add_features(&feat, "256", ":,");
362  break;
363  case 'c':
365  break;
366  case 'D':
367  flags |= CLIENT_NOFORK;
368  break;
369  case 'C':
370  if (flags & CLIENT_CONTROL)
372  else
374  break;
375  case 'f':
376  if (!fflag) {
377  fflag = 1;
378  for (i = 0; i < cfg_nfiles; i++)
379  free(cfg_files[i]);
380  cfg_nfiles = 0;
381  }
383  sizeof *cfg_files);
385  cfg_quiet = 0;
386  break;
387  case 'V':
388  printf("%s %s\n", getprogname(), getversion());
389  exit(0);
390  case 'l':
391  flags |= CLIENT_LOGIN;
392  break;
393  case 'L':
394  free(label);
395  label = xstrdup(optarg);
396  break;
397  case 'N':
399  break;
400  case 'q':
401  break;
402  case 'S':
403  free(path);
404  path = xstrdup(optarg);
405  break;
406  case 'T':
407  tty_add_features(&feat, optarg, ":,");
408  break;
409  case 'u':
410  flags |= CLIENT_UTF8;
411  break;
412  case 'v':
413  log_add_level();
414  break;
415  default:
416  usage();
417  }
418  }
419  argc -= optind;
420  argv += optind;
421 
422  if (shell_command != NULL && argc != 0)
423  usage();
424  if ((flags & CLIENT_NOFORK) && argc != 0)
425  usage();
426 
427  if ((ptm_fd = getptmfd()) == -1)
428  err(1, "getptmfd");
429  if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd "
430  "recvfd proc exec tty ps", NULL) != 0)
431  err(1, "pledge");
432 
433  /*
434  * tmux is a UTF-8 terminal, so if TMUX is set, assume UTF-8.
435  * Otherwise, if the user has set LC_ALL, LC_CTYPE or LANG to contain
436  * UTF-8, it is a safe assumption that either they are using a UTF-8
437  * terminal, or if not they know that output from UTF-8-capable
438  * programs may be wrong.
439  */
440  if (getenv("TMUX") != NULL)
441  flags |= CLIENT_UTF8;
442  else {
443  s = getenv("LC_ALL");
444  if (s == NULL || *s == '\0')
445  s = getenv("LC_CTYPE");
446  if (s == NULL || *s == '\0')
447  s = getenv("LANG");
448  if (s == NULL || *s == '\0')
449  s = "";
450  if (strcasestr(s, "UTF-8") != NULL ||
451  strcasestr(s, "UTF8") != NULL)
452  flags |= CLIENT_UTF8;
453  }
454 
458  for (oe = options_table; oe->name != NULL; oe++) {
459  if (oe->scope & OPTIONS_TABLE_SERVER)
461  if (oe->scope & OPTIONS_TABLE_SESSION)
463  if (oe->scope & OPTIONS_TABLE_WINDOW)
465  }
466 
467  /*
468  * The default shell comes from SHELL or from the user's passwd entry
469  * if available.
470  */
471  options_set_string(global_s_options, "default-shell", 0, "%s",
472  getshell());
473 
474  /* Override keys to vi if VISUAL or EDITOR are set. */
475  if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
476  options_set_string(global_options, "editor", 0, "%s", s);
477  if (strrchr(s, '/') != NULL)
478  s = strrchr(s, '/') + 1;
479  if (strstr(s, "vi") != NULL)
480  keys = MODEKEY_VI;
481  else
482  keys = MODEKEY_EMACS;
483  options_set_number(global_s_options, "status-keys", keys);
484  options_set_number(global_w_options, "mode-keys", keys);
485  }
486 
487  /*
488  * If socket is specified on the command-line with -S or -L, it is
489  * used. Otherwise, $TMUX is checked and if that fails "default" is
490  * used.
491  */
492  if (path == NULL && label == NULL) {
493  s = getenv("TMUX");
494  if (s != NULL && *s != '\0' && *s != ',') {
495  path = xstrdup(s);
496  path[strcspn(path, ",")] = '\0';
497  }
498  }
499  if (path == NULL) {
500  if ((path = make_label(label, &cause)) == NULL) {
501  if (cause != NULL) {
502  fprintf(stderr, "%s\n", cause);
503  free(cause);
504  }
505  exit(1);
506  }
508  }
509  socket_path = path;
510  free(label);
511 
512  /* Pass control to the client. */
513  exit(client_main(osdep_event_init(), argc, argv, flags, feat));
514 }
int cfg_quiet
Definition: cfg.c:35
u_int cfg_nfiles
Definition: cfg.c:37
char ** cfg_files
Definition: cfg.c:36
int client_main(struct event_base *base, int argc, char **argv, uint64_t flags, int feat)
Definition: client.c:232
char * strcasestr(const char *, const char *)
const char * getprogname(void)
char * strsep(char **, const char *)
int clock_gettime(int, struct timespec *)
#define pledge(s, p)
Definition: compat.h:126
#define getopt(ac, av, o)
Definition: compat.h:438
#define CLOCK_MONOTONIC
Definition: compat.h:272
void errx(int, const char *,...)
#define optarg
Definition: compat.h:443
#define CLOCK_REALTIME
Definition: compat.h:269
int getptmfd(void)
#define _PATH_BSHELL
Definition: compat.h:98
void err(int, const char *,...)
#define __dead
Definition: compat.h:63
#define optind
Definition: compat.h:440
struct environ * environ_create(void)
Definition: environ.c:44
void environ_put(struct environ *env, const char *var, int flags)
Definition: environ.c:150
struct environ_entry * environ_find(struct environ *env, const char *name)
Definition: environ.c:99
void environ_set(struct environ *env, const char *name, int flags, const char *fmt,...)
Definition: environ.c:109
const char * name
Definition: layout-set.c:38
void log_add_level(void)
Definition: log.c:44
void log_debug(const char *msg,...)
Definition: log.c:130
const struct options_table_entry options_table[]
struct options_entry * options_default(struct options *oo, const struct options_table_entry *oe)
Definition: options.c:258
struct options * options_create(struct options *parent)
Definition: options.c:171
struct options_entry * options_set_number(struct options *oo, const char *name, long long value)
Definition: options.c:752
struct options_entry * options_set_string(struct options *oo, const char *name, int append, const char *fmt,...)
Definition: options.c:712
struct event_base * osdep_event_init(void)
Definition: osdep-aix.c:92
Definition: tmux.h:1160
char * value
Definition: tmux.h:1162
Definition: tmux.h:1830
const char * name
Definition: tmux.h:1831
int flags
Definition: tmux.h:1835
int scope
Definition: tmux.h:1834
int ptm_fd
Definition: tmux.c:43
const char * find_home(void)
Definition: tmux.c:299
uint64_t get_timer(void)
Definition: tmux.c:247
int main(int argc, char **argv)
Definition: tmux.c:326
static int areshell(const char *)
Definition: tmux.c:92
struct environ * global_environ
Definition: tmux.c:39
const char * sig2name(int signo)
Definition: tmux.c:261
int checkshell(const char *shell)
Definition: tmux.c:80
struct options * global_s_options
Definition: tmux.c:37
const char * find_cwd(void)
Definition: tmux.c:274
const char * socket_path
Definition: tmux.c:42
static char * expand_path(const char *path, const char *home)
Definition: tmux.c:109
static const char * getshell(void)
Definition: tmux.c:63
const char * getversion(void)
Definition: tmux.c:320
struct timeval start_time
Definition: tmux.c:41
struct options * global_w_options
Definition: tmux.c:38
static void expand_paths(const char *s, char ***paths, u_int *n, int ignore_errors)
Definition: tmux.c:142
const char * shell_command
Definition: tmux.c:44
static void usage(void)
Definition: tmux.c:53
static char * make_label(const char *, char **)
Definition: tmux.c:187
void setblocking(int fd, int state)
Definition: tmux.c:233
struct options * global_options
Definition: tmux.c:36
void tty_add_features(int *, const char *, const char *)
Definition: tty-features.c:262
#define CLIENT_UTF8
Definition: tmux.h:1670
#define TMUX_CONF
Definition: tmux.h:73
#define OPTIONS_TABLE_WINDOW
Definition: tmux.h:1823
#define CLIENT_NOSTARTSERVER
Definition: tmux.h:1666
#define CLIENT_NOFORK
Definition: tmux.h:1684
#define CLIENT_CONTROL
Definition: tmux.h:1667
#define MODEKEY_VI
Definition: tmux.h:595
char ** environ
#define OPTIONS_TABLE_SESSION
Definition: tmux.h:1822
#define CLIENT_DEFAULTSOCKET
Definition: tmux.h:1681
#define TMUX_SOCK
Definition: tmux.h:76
#define OPTIONS_TABLE_SERVER
Definition: tmux.h:1821
#define MODEKEY_EMACS
Definition: tmux.h:594
#define CLIENT_CONTROLCONTROL
Definition: tmux.h:1668
#define CLIENT_LOGIN
Definition: tmux.h:1655
char * xstrndup(const char *str, size_t maxlen)
Definition: xmalloc.c:99
int xsnprintf(char *str, size_t len, const char *fmt,...)
Definition: xmalloc.c:135
void * xreallocarray(void *ptr, size_t nmemb, size_t size)
Definition: xmalloc.c:61
int xasprintf(char **ret, const char *fmt,...)
Definition: xmalloc.c:109
char * xstrdup(const char *str)
Definition: xmalloc.c:89