Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 415 lines (360 sloc) 9.46 kb
c2acb99 @orebokech Import upstream snapshot from SVN r2630
orebokech authored
1 /* $Id: tmux.c 2620 2011-10-23 15:08:58Z tcunha $ */
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
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/stat.h>
21
22 #include <errno.h>
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
23 #include <event.h>
77c63de @orebokech Import upstream version 1.4
orebokech authored
24 #include <fcntl.h>
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
25 #include <pwd.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "tmux.h"
31
32 #if defined(DEBUG) && defined(__OpenBSD__)
33 extern char *malloc_options;
34 #endif
35
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
36 struct options global_options; /* server options */
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
37 struct options global_s_options; /* session options */
38 struct options global_w_options; /* window options */
39 struct environ global_environ;
40
fb53a63 @kfebert Imported Upstream version 1.3
kfebert authored
41 struct event_base *ev_base;
42
77c63de @orebokech Import upstream version 1.4
orebokech authored
43 char *cfg_file;
44 char *shell_cmd;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
45 int debug_level;
46 time_t start_time;
77c63de @orebokech Import upstream version 1.4
orebokech authored
47 char socket_path[MAXPATHLEN];
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
48 int login_shell;
77c63de @orebokech Import upstream version 1.4
orebokech authored
49 char *environ_path;
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
50 pid_t environ_pid = -1;
51 int environ_idx = -1;
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
52
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
53 __dead void usage(void);
77c63de @orebokech Import upstream version 1.4
orebokech authored
54 void parseenvironment(void);
55 char *makesocketpath(const char *);
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
56
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
57 #ifndef HAVE___PROGNAME
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
58 char *__progname = (char *) "tmux";
59 #endif
60
61 __dead void
62 usage(void)
63 {
64 fprintf(stderr,
77c63de @orebokech Import upstream version 1.4
orebokech authored
65 "usage: %s [-28lquvV] [-c shell-command] [-f file] [-L socket-name]\n"
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
66 " [-S socket-path] [command [flags]]\n",
67 __progname);
68 exit(1);
69 }
70
71 void
72 logfile(const char *name)
73 {
74 char *path;
75
76 log_close();
77 if (debug_level > 0) {
78 xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid());
79 log_open_file(debug_level, path);
80 xfree(path);
81 }
82 }
83
84 const char *
85 getshell(void)
86 {
87 struct passwd *pw;
88 const char *shell;
89
90 shell = getenv("SHELL");
91 if (checkshell(shell))
92 return (shell);
93
94 pw = getpwuid(getuid());
95 if (pw != NULL && checkshell(pw->pw_shell))
96 return (pw->pw_shell);
97
98 return (_PATH_BSHELL);
99 }
100
101 int
102 checkshell(const char *shell)
103 {
b016948 @orebokech Import upstream snapshot from SVN r2608
orebokech authored
104 if (shell == NULL || *shell == '\0' || *shell != '/')
105 return (0);
106 if (areshell(shell))
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
107 return (0);
108 if (access(shell, X_OK) != 0)
109 return (0);
110 return (1);
111 }
112
113 int
114 areshell(const char *shell)
115 {
116 const char *progname, *ptr;
117
118 if ((ptr = strrchr(shell, '/')) != NULL)
119 ptr++;
120 else
121 ptr = shell;
122 progname = __progname;
123 if (*progname == '-')
124 progname++;
125 if (strcmp(ptr, progname) == 0)
126 return (1);
127 return (0);
128 }
129
c2acb99 @orebokech Import upstream snapshot from SVN r2630
orebokech authored
130 const char*
131 get_full_path(const char *wd, const char *path)
132 {
133 static char newpath[MAXPATHLEN];
134 char oldpath[MAXPATHLEN];
135
136 if (getcwd(oldpath, sizeof oldpath) == NULL)
137 return (NULL);
138 if (chdir(wd) != 0)
139 return (NULL);
140 if (realpath(path, newpath) != 0)
141 return (NULL);
142 chdir(oldpath);
143 return (newpath);
144 }
145
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
146 void
77c63de @orebokech Import upstream version 1.4
orebokech authored
147 parseenvironment(void)
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
148 {
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
149 char *env, path[256];
150 long pid;
151 int idx;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
152
153 if ((env = getenv("TMUX")) == NULL)
154 return;
155
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
156 if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &idx) != 3)
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
157 return;
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
158 environ_path = xstrdup(path);
159 environ_pid = pid;
160 environ_idx = idx;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
161 }
162
163 char *
77c63de @orebokech Import upstream version 1.4
orebokech authored
164 makesocketpath(const char *label)
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
165 {
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
166 char base[MAXPATHLEN], *path, *s;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
167 struct stat sb;
168 u_int uid;
169
170 uid = getuid();
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
171 if ((s = getenv("TMPDIR")) == NULL || *s == '\0')
172 xsnprintf(base, sizeof base, "%s/tmux-%u", _PATH_TMP, uid);
173 else
174 xsnprintf(base, sizeof base, "%s/tmux-%u", s, uid);
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
175
176 if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
177 return (NULL);
178
179 if (lstat(base, &sb) != 0)
180 return (NULL);
181 if (!S_ISDIR(sb.st_mode)) {
182 errno = ENOTDIR;
183 return (NULL);
184 }
185 if (sb.st_uid != uid || (sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) {
186 errno = EACCES;
187 return (NULL);
188 }
189
190 xasprintf(&path, "%s/%s", base, label);
191 return (path);
192 }
193
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
194 void
195 setblocking(int fd, int state)
196 {
197 int mode;
198
199 if ((mode = fcntl(fd, F_GETFL)) != -1) {
200 if (!state)
201 mode |= O_NONBLOCK;
202 else
203 mode &= ~O_NONBLOCK;
204 fcntl(fd, F_SETFL, mode);
205 }
206 }
207
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
208 __dead void
209 shell_exec(const char *shell, const char *shellcmd)
210 {
211 const char *shellname, *ptr;
212 char *argv0;
213
214 ptr = strrchr(shell, '/');
215 if (ptr != NULL && *(ptr + 1) != '\0')
216 shellname = ptr + 1;
217 else
218 shellname = shell;
219 if (login_shell)
220 xasprintf(&argv0, "-%s", shellname);
221 else
222 xasprintf(&argv0, "%s", shellname);
223 setenv("SHELL", shell, 1);
224
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
225 setblocking(STDIN_FILENO, 1);
226 setblocking(STDOUT_FILENO, 1);
227 setblocking(STDERR_FILENO, 1);
77c63de @orebokech Import upstream version 1.4
orebokech authored
228 closefrom(STDERR_FILENO + 1);
229
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
230 execl(shell, argv0, "-c", shellcmd, (char *) NULL);
231 fatal("execl failed");
232 }
233
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
234 int
235 main(int argc, char **argv)
236 {
77c63de @orebokech Import upstream version 1.4
orebokech authored
237 struct passwd *pw;
238 struct keylist *keylist;
239 char *s, *path, *label, *home, **var;
240 int opt, flags, quiet, keys;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
241
242 #if defined(DEBUG) && defined(__OpenBSD__)
243 malloc_options = (char *) "AFGJPX";
244 #endif
245
77c63de @orebokech Import upstream version 1.4
orebokech authored
246 quiet = flags = 0;
247 label = path = NULL;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
248 login_shell = (**argv == '-');
77c63de @orebokech Import upstream version 1.4
orebokech authored
249 while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUvV")) != -1) {
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
250 switch (opt) {
251 case '2':
252 flags |= IDENTIFY_256COLOURS;
253 flags &= ~IDENTIFY_88COLOURS;
254 break;
255 case '8':
256 flags |= IDENTIFY_88COLOURS;
257 flags &= ~IDENTIFY_256COLOURS;
258 break;
259 case 'c':
77c63de @orebokech Import upstream version 1.4
orebokech authored
260 if (shell_cmd != NULL)
261 xfree(shell_cmd);
262 shell_cmd = xstrdup(optarg);
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
263 break;
77c63de @orebokech Import upstream version 1.4
orebokech authored
264 case 'V':
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
265 printf("%s %s\n", __progname, VERSION);
77c63de @orebokech Import upstream version 1.4
orebokech authored
266 exit(0);
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
267 case 'f':
268 if (cfg_file != NULL)
269 xfree(cfg_file);
270 cfg_file = xstrdup(optarg);
271 break;
272 case 'l':
273 login_shell = 1;
274 break;
275 case 'L':
276 if (label != NULL)
277 xfree(label);
278 label = xstrdup(optarg);
279 break;
280 case 'q':
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
281 quiet = 1;
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
282 break;
283 case 'S':
284 if (path != NULL)
285 xfree(path);
286 path = xstrdup(optarg);
287 break;
288 case 'u':
289 flags |= IDENTIFY_UTF8;
290 break;
291 case 'v':
292 debug_level++;
293 break;
294 default:
295 usage();
296 }
297 }
298 argc -= optind;
299 argv += optind;
300
77c63de @orebokech Import upstream version 1.4
orebokech authored
301 if (shell_cmd != NULL && argc != 0)
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
302 usage();
303
304 log_open_tty(debug_level);
305
306 if (!(flags & IDENTIFY_UTF8)) {
307 /*
308 * If the user has set whichever of LC_ALL, LC_CTYPE or LANG
309 * exist (in that order) to contain UTF-8, it is a safe
310 * assumption that either they are using a UTF-8 terminal, or
311 * if not they know that output from UTF-8-capable programs may
312 * be wrong.
313 */
c2acb99 @orebokech Import upstream snapshot from SVN r2630
orebokech authored
314 if ((s = getenv("LC_ALL")) == NULL || *s == '\0') {
315 if ((s = getenv("LC_CTYPE")) == NULL || *s == '\0')
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
316 s = getenv("LANG");
317 }
318 if (s != NULL && (strcasestr(s, "UTF-8") != NULL ||
319 strcasestr(s, "UTF8") != NULL))
320 flags |= IDENTIFY_UTF8;
321 }
322
323 environ_init(&global_environ);
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
324 for (var = environ; *var != NULL; var++)
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
325 environ_put(&global_environ, *var);
326
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
327 options_init(&global_options, NULL);
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
328 options_table_populate_tree(server_options_table, &global_options);
329 options_set_number(&global_options, "quiet", quiet);
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
330
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
331 options_init(&global_s_options, NULL);
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
332 options_table_populate_tree(session_options_table, &global_s_options);
333 options_set_string(&global_s_options, "default-shell", "%s", getshell());
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
334
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
335 options_init(&global_w_options, NULL);
336 options_table_populate_tree(window_options_table, &global_w_options);
337
338 /* Set the prefix option (its a list, so not in the table). */
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
339 keylist = xmalloc(sizeof *keylist);
340 ARRAY_INIT(keylist);
341 ARRAY_ADD(keylist, '\002');
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
342 options_set_data(&global_s_options, "prefix", keylist, xfree);
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
343
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
344 /* Enable UTF-8 if the first client is on UTF-8 terminal. */
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
345 if (flags & IDENTIFY_UTF8) {
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
346 options_set_number(&global_s_options, "status-utf8", 1);
347 options_set_number(&global_s_options, "mouse-utf8", 1);
348 options_set_number(&global_w_options, "utf8", 1);
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
349 }
350
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
351 /* Override keys to vi if VISUAL or EDITOR are set. */
77c63de @orebokech Import upstream version 1.4
orebokech authored
352 if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
353 if (strrchr(s, '/') != NULL)
354 s = strrchr(s, '/') + 1;
355 if (strstr(s, "vi") != NULL)
356 keys = MODEKEY_VI;
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
357 else
358 keys = MODEKEY_EMACS;
359 options_set_number(&global_s_options, "status-keys", keys);
360 options_set_number(&global_w_options, "mode-keys", keys);
77c63de @orebokech Import upstream version 1.4
orebokech authored
361 }
362
363 /* Locate the configuration file. */
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
364 if (cfg_file == NULL) {
365 home = getenv("HOME");
366 if (home == NULL || *home == '\0') {
367 pw = getpwuid(getuid());
368 if (pw != NULL)
369 home = pw->pw_dir;
370 }
371 xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG);
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
372 if (access(cfg_file, R_OK) != 0 && errno == ENOENT) {
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
373 xfree(cfg_file);
374 cfg_file = NULL;
375 }
376 }
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
377
378 /*
77c63de @orebokech Import upstream version 1.4
orebokech authored
379 * Figure out the socket path. If specified on the command-line with -S
380 * or -L, use it, otherwise try $TMUX or assume -L default.
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
381 */
77c63de @orebokech Import upstream version 1.4
orebokech authored
382 parseenvironment();
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
383 if (path == NULL) {
77c63de @orebokech Import upstream version 1.4
orebokech authored
384 /* If no -L, use the environment. */
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
385 if (label == NULL) {
77c63de @orebokech Import upstream version 1.4
orebokech authored
386 if (environ_path != NULL)
387 path = xstrdup(environ_path);
388 else
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
389 label = xstrdup("default");
390 }
391
392 /* -L or default set. */
393 if (label != NULL) {
77c63de @orebokech Import upstream version 1.4
orebokech authored
394 if ((path = makesocketpath(label)) == NULL) {
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
395 log_warn("can't create socket");
396 exit(1);
397 }
398 }
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
399 }
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
400 if (label != NULL)
401 xfree(label);
77c63de @orebokech Import upstream version 1.4
orebokech authored
402 if (realpath(path, socket_path) == NULL)
403 strlcpy(socket_path, path, sizeof socket_path);
404 xfree(path);
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
405
77c63de @orebokech Import upstream version 1.4
orebokech authored
406 #ifdef HAVE_SETPROCTITLE
407 /* Set process title. */
408 setproctitle("%s (%s)", __progname, socket_path);
409 #endif
dda8e8e @kfebert Imported Upstream version 1.2
kfebert authored
410
77c63de @orebokech Import upstream version 1.4
orebokech authored
411 /* Pass control to the client. */
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
412 ev_base = osdep_event_init();
77c63de @orebokech Import upstream version 1.4
orebokech authored
413 exit(client_main(argc, argv, flags));
8fade26 Imported Upstream version 1.1
Karl Ferdinand Ebert authored
414 }
Something went wrong with that request. Please try again.