The branch, master has been updated
       via  4538c269d0b366a770a5a5ebfe0c5007569edbc1 (commit)
      from  446eb11cdeba97a24996cee36ba331491aba6211 (commit)

- Log -----------------------------------------------------------------
commit 4538c269d0b366a770a5a5ebfe0c5007569edbc1
Author: Nicholas Marriott <[email protected]>
Commit: Nicholas Marriott <[email protected]>

    Alter how tmux handles the working directory to internally use file 
descriptors
    rather than strings.
    
    - Each session still has a current working directory.
    
    - New sessions still get their working directory from the client that 
created
      them or its attached session if any.
    
    - New windows are created by default in the session working directory.
    
    - The -c flag to new, neww, splitw allows the working directory to be
      overridden.
    
    - The -c flag to attach let's the session working directory be changed.
    
    - The default-path option has been removed.
    
    To get the equivalent to default-path '.', do:
    
            bind c neww -c $PWD
    
    To get the equivalent of default-path '', do:
    
            bind c neww -c '#{pane_current_path}'
    
    The equivalent of default-path '~' is left as an exercise for the reader.
    
    This also changes the client identify protocol to be a set of messages 
rather
    than one as well as some other changes that should make it easier to make
    backwards-compatible protocol changes in future.
---
 client.c             |   60 +++++++++---------------
 cmd-attach-session.c |   68 +++++++++++++++++++++++----
 cmd-load-buffer.c    |   30 ++++++------
 cmd-new-session.c    |   74 ++++++++++++++++++------------
 cmd-new-window.c     |   41 +++++++++++++++--
 cmd-queue.c          |   24 ----------
 cmd-save-buffer.c    |   54 ++++++++++------------
 cmd-split-window.c   |   40 ++++++++++++++--
 format.c             |    3 -
 options-table.c      |    5 --
 server-client.c      |  125 +++++++++++++++++++++++++++++++++-----------------
 server-fn.c          |    8 ++--
 session.c            |   17 +++----
 tmux.1               |   22 ++-------
 tmux.c               |   28 +----------
 tmux.h               |   56 ++++++----------------
 window.c             |   16 +++---
 17 files changed, 363 insertions(+), 308 deletions(-)

diff --git a/client.c b/client.c
index 0a1c8da..6179187 100644
--- a/client.c
+++ b/client.c
@@ -53,7 +53,6 @@ int           client_attached;
 int            client_get_lock(char *);
 int            client_connect(char *, int);
 void           client_send_identify(int);
-void           client_send_environ(void);
 int            client_write_one(enum msgtype, int, const void *, size_t);
 int            client_write_server(enum msgtype, const void *, size_t);
 void           client_update_event(void);
@@ -261,8 +260,7 @@ client_main(int argc, char **argv, int flags)
        /* Establish signal handlers. */
        set_signals(client_signal);
 
-       /* Send initial environment. */
-       client_send_environ();
+       /* Send identify messages. */
        client_send_identify(flags);
 
        /* Send first command. */
@@ -320,48 +318,38 @@ client_main(int argc, char **argv, int flags)
        return (client_exitval);
 }
 
-/* Send identify message to server with the file descriptors. */
+/* Send identify messages to server. */
 void
 client_send_identify(int flags)
 {
-       struct msg_identify_data        data;
-       char                           *term;
-       int                             fd;
+       const char      *s;
+       char            **ss;
+       int              fd;
 
-       data.flags = flags;
+       client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
 
-       if (getcwd(data.cwd, sizeof data.cwd) == NULL)
-               *data.cwd = '\0';
+       if ((s = getenv("TERM")) == NULL)
+               s = "";
+       client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
 
-       term = getenv("TERM");
-       if (term == NULL ||
-           strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
-               *data.term = '\0';
+       if ((s = ttyname(STDIN_FILENO)) == NULL)
+               s = "";
+       client_write_one(MSG_IDENTIFY_TTYNAME, -1, s, strlen(s) + 1);
+
+       if ((fd = open(".", O_RDONLY)) == -1)
+               fd = open("/", O_RDONLY);
+       client_write_one(MSG_IDENTIFY_CWD, fd, NULL, 0);
 
-#ifdef __CYGWIN__
-       snprintf(&data.ttyname, sizeof data.ttyname, "%s",
-           ttyname(STDIN_FILENO));
-#else
        if ((fd = dup(STDIN_FILENO)) == -1)
                fatal("dup failed");
-#endif
-       imsg_compose(&client_ibuf,
-           MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
-       client_update_event();
-}
+       client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0);
 
-/* Forward entire environment to server. */
-void
-client_send_environ(void)
-{
-       struct msg_environ_data data;
-       char                  **var;
+       for (ss = environ; *ss != NULL; ss++)
+               client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, strlen(*ss) + 
1);
 
-       for (var = environ; *var != NULL; var++) {
-               if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
-                       continue;
-               client_write_server(MSG_ENVIRON, &data, sizeof data);
-       }
+       client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0);
+
+       client_update_event();
 }
 
 /* Helper to send one message. */
@@ -604,8 +592,6 @@ client_dispatch_wait(void *data0)
                case MSG_EXITED:
                        imsg_free(&imsg);
                        return (-1);
-               default:
-                       fatalx("unexpected message");
                }
 
                imsg_free(&imsg);
@@ -684,8 +670,6 @@ client_dispatch_attached(void)
                        system(data);
                        client_write_server(MSG_UNLOCK, NULL, 0);
                        break;
-               default:
-                       fatalx("unexpected message");
                }
 
                imsg_free(&imsg);
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 7a952e5..f78a89f 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -18,7 +18,11 @@
 
 #include <sys/types.h>
 
+#include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "tmux.h"
 
@@ -30,21 +34,25 @@ enum cmd_retval     cmd_attach_session_exec(struct cmd *, 
struct cmd_q *);
 
 const struct cmd_entry cmd_attach_session_entry = {
        "attach-session", "attach",
-       "drt:", 0, 0,
-       "[-dr] " CMD_TARGET_SESSION_USAGE,
+       "c:drt:", 0, 0,
+       "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
        CMD_CANTNEST|CMD_STARTSERVER,
        NULL,
        cmd_attach_session_exec
 };
 
 enum cmd_retval
-cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag)
+cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
+    const char *cflag)
 {
-       struct session  *s;
-       struct client   *c;
-       const char      *update;
-       char            *cause;
-       u_int            i;
+       struct session          *s;
+       struct client           *c;
+       const char              *update;
+       char                    *cause;
+       u_int                    i;
+       int                      fd;
+       struct format_tree      *ft;
+       char                    *cp;
 
        if (RB_EMPTY(&sessions)) {
                cmdq_error(cmdq, "no sessions");
@@ -73,6 +81,27 @@ cmd_attach_session(struct cmd_q *cmdq, const char* tflag, 
int dflag, int rflag)
                        }
                }
 
+               if (cflag != NULL) {
+                       ft = format_create();
+                       if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
+                               format_client(ft, c);
+                       format_session(ft, s);
+                       format_winlink(ft, s, s->curw);
+                       format_window_pane(ft, s->curw->window->active);
+                       cp = format_expand(ft, cflag);
+                       format_free(ft);
+
+                       fd = open(cp, O_RDONLY|O_DIRECTORY);
+                       free(cp);
+                       if (fd == -1) {
+                               cmdq_error(cmdq, "bad working directory: %s",
+                                   strerror(errno));
+                               return (CMD_RETURN_ERROR);
+                       }
+                       close(s->cwd);
+                       s->cwd = fd;
+               }
+
                cmdq->client->session = s;
                notify_attached_session_changed(cmdq->client);
                session_update_activity(s);
@@ -85,6 +114,27 @@ cmd_attach_session(struct cmd_q *cmdq, const char* tflag, 
int dflag, int rflag)
                        return (CMD_RETURN_ERROR);
                }
 
+               if (cflag != NULL) {
+                       ft = format_create();
+                       if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
+                               format_client(ft, c);
+                       format_session(ft, s);
+                       format_winlink(ft, s, s->curw);
+                       format_window_pane(ft, s->curw->window->active);
+                       cp = format_expand(ft, cflag);
+                       format_free(ft);
+
+                       fd = open(cp, O_RDONLY|O_DIRECTORY);
+                       free(cp);
+                       if (fd == -1) {
+                               cmdq_error(cmdq, "bad working directory: %s",
+                                   strerror(errno));
+                               return (CMD_RETURN_ERROR);
+                       }
+                       close(s->cwd);
+                       s->cwd = fd;
+               }
+
                if (rflag)
                        cmdq->client->flags |= CLIENT_READONLY;
 
@@ -115,5 +165,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q 
*cmdq)
        struct args     *args = self->args;
 
        return (cmd_attach_session(cmdq, args_get(args, 't'),
-           args_has(args, 'd'), args_has(args, 'r')));
+           args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c')));
 }
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 82b8f57..4acbab5 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -49,11 +50,11 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
        struct client   *c = cmdq->client;
        struct session  *s;
        FILE            *f;
-       const char      *path, *newpath, *wd;
+       const char      *path;
        char            *pdata, *new_pdata, *cause;
        size_t           psize;
        u_int            limit;
-       int              ch, error, buffer, *buffer_ptr;
+       int              ch, error, buffer, *buffer_ptr, cwd, fd;
 
        if (!args_has(args, 'b'))
                buffer = -1;
@@ -81,20 +82,17 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
                return (CMD_RETURN_WAIT);
        }
 
-       if (c != NULL)
-               wd = c->cwd;
-       else if ((s = cmd_current_session(cmdq, 0)) != NULL) {
-               wd = options_get_string(&s->options, "default-path");
-               if (*wd == '\0')
-                       wd = s->cwd;
-       } else
-               wd = NULL;
-       if (wd != NULL && *wd != '\0') {
-               newpath = get_full_path(wd, path);
-               if (newpath != NULL)
-                       path = newpath;
-       }
-       if ((f = fopen(path, "rb")) == NULL) {
+       if (c != NULL && c->session == NULL)
+               cwd = c->cwd;
+       else if ((s = cmd_current_session(cmdq, 0)) != NULL)
+               cwd = s->cwd;
+       else
+               cwd = AT_FDCWD;
+
+       if ((fd = openat(cwd, path, O_RDONLY)) == -1 ||
+           (f = fdopen(fd, "rb")) == NULL) {
+               if (fd != -1)
+                       close(fd);
                cmdq_error(cmdq, "%s: %s", path, strerror(errno));
                return (CMD_RETURN_ERROR);
        }
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 38c79a6..3ce2439 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -18,6 +18,8 @@
 
 #include <sys/types.h>
 
+#include <errno.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -47,18 +49,15 @@ enum cmd_retval
 cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
 {
        struct args             *args = self->args;
-       struct client           *c = cmdq->client;
+       struct client           *c = cmdq->client, *c0;
        struct session          *s, *groupwith;
        struct window           *w;
        struct environ           env;
        struct termios           tio, *tiop;
-       struct passwd           *pw;
-       const char              *newname, *target, *update, *base, *cwd;
-       const char              *errstr, *template;
+       const char              *newname, *target, *update, *errstr, *template;
        char                    *cmd, *cause, *cp;
-       int                      detached, idx;
+       int                      detached, already_attached, idx, cwd, fd = -1;
        u_int                    sx, sy;
-       int                      already_attached;
        struct format_tree      *ft;
 
        if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
@@ -75,7 +74,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
                if (session_find(newname) != NULL) {
                        if (args_has(args, 'A')) {
                                return (cmd_attach_session(cmdq, newname,
-                                   args_has(args, 'D'), 0));
+                                   args_has(args, 'D'), 0, NULL));
                        }
                        cmdq_error(cmdq, "duplicate session: %s", newname);
                        return (CMD_RETURN_ERROR);
@@ -100,6 +99,31 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
        if (c != NULL && c->session != NULL)
                already_attached = 1;
 
+       /* Get the new session working directory. */
+       if (args_has(args, 'c')) {
+               ft = format_create();
+               if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL)
+                       format_client(ft, c0);
+               cp = format_expand(ft, args_get(args, 'c'));
+               format_free(ft);
+
+               fd = open(cp, O_RDONLY|O_DIRECTORY);
+               free(cp);
+               if (fd == -1) {
+                       cmdq_error(cmdq, "bad working directory: %s",
+                           strerror(errno));
+                       return (CMD_RETURN_ERROR);
+               }
+               cwd = fd;
+       } else if (c->session == NULL)
+               cwd = c->cwd;
+       else if ((c0 = cmd_current_client(cmdq)) != NULL)
+               cwd = c0->session->cwd;
+       else {
+               fd = open(".", O_RDONLY);
+               cwd = fd;
+       }
+
        /*
         * Save the termios settings, part of which is used for new windows in
         * this session.
@@ -121,26 +145,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
                if (server_client_open(c, NULL, &cause) != 0) {
                        cmdq_error(cmdq, "open terminal failed: %s", cause);
                        free(cause);
-                       return (CMD_RETURN_ERROR);
+                       goto error;
                }
        }
 
-       /* Get the new session working directory. */
-       if (c != NULL && c->cwd != NULL)
-               base = c->cwd;
-       else {
-               pw = getpwuid(getuid());
-               if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
-                       base = pw->pw_dir;
-               else
-                       base = "/";
-       }
-       if (args_has(args, 'c'))
-               cwd = args_get(args, 'c');
-       else
-               cwd = options_get_string(&global_s_options, "default-path");
-       cwd = cmd_default_path(base, base, cwd);
-
        /* Find new session size. */
        if (c != NULL) {
                sx = c->tty.sx;
@@ -153,14 +161,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
                sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
                if (errstr != NULL) {
                        cmdq_error(cmdq, "width %s", errstr);
-                       return (CMD_RETURN_ERROR);
+                       goto error;
                }
        }
        if (detached && args_has(args, 'y')) {
                sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
                if (errstr != NULL) {
                        cmdq_error(cmdq, "height %s", errstr);
-                       return (CMD_RETURN_ERROR);
+                       goto error;
                }
        }
        if (sy > 0 && options_get_number(&global_s_options, "status"))
@@ -190,7 +198,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
        if (s == NULL) {
                cmdq_error(cmdq, "create session failed: %s", cause);
                free(cause);
-               return (CMD_RETURN_ERROR);
+               goto error;
        }
        environ_free(&env);
 
@@ -241,8 +249,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
                        template = NEW_SESSION_TEMPLATE;
 
                ft = format_create();
-               if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
-                       format_client(ft, c);
+               if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL)
+                       format_client(ft, c0);
                format_session(ft, s);
 
                cp = format_expand(ft, template);
@@ -254,5 +262,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
 
        if (!detached)
                cmdq->client_exit = 0;
+
+       if (fd != -1)
+               close(fd);
        return (CMD_RETURN_NORMAL);
+
+error:
+       if (fd != -1)
+               close(fd);
+       return (CMD_RETURN_ERROR);
 }
diff --git a/cmd-new-window.c b/cmd-new-window.c
index e5658b3..f6a925b 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -18,7 +18,11 @@
 
 #include <sys/types.h>
 
+#include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "tmux.h"
 
@@ -45,9 +49,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
        struct session          *s;
        struct winlink          *wl;
        struct client           *c;
-       const char              *cmd, *cwd, *template;
+       const char              *cmd, *template;
        char                    *cause, *cp;
-       int                      idx, last, detached;
+       int                      idx, last, detached, cwd, fd = -1;
        struct format_tree      *ft;
 
        if (args_has(args, 'a')) {
@@ -102,7 +106,29 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
                cmd = options_get_string(&s->options, "default-command");
        else
                cmd = args->argv[0];
-       cwd = cmdq_default_path(cmdq, args_get(args, 'c'));
+
+       if (args_has(args, 'c')) {
+               ft = format_create();
+               if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
+                       format_client(ft, c);
+               format_session(ft, s);
+               format_winlink(ft, s, s->curw);
+               format_window_pane(ft, s->curw->window->active);
+               cp = format_expand(ft, args_get(args, 'c'));
+               format_free(ft);
+
+               fd = open(cp, O_RDONLY|O_DIRECTORY);
+               free(cp);
+               if (fd == -1) {
+                       cmdq_error(cmdq, "bad working directory: %s",
+                           strerror(errno));
+                       return (CMD_RETURN_ERROR);
+               }
+               cwd = fd;
+       } else if (cmdq->client->session == NULL)
+               cwd = cmdq->client->cwd;
+       else
+               cwd = s->cwd;
 
        if (idx == -1)
                idx = -1 - options_get_number(&s->options, "base-index");
@@ -110,7 +136,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
        if (wl == NULL) {
                cmdq_error(cmdq, "create window failed: %s", cause);
                free(cause);
-               return (CMD_RETURN_ERROR);
+               goto error;
        }
        if (!detached) {
                session_select(s, wl->idx);
@@ -136,5 +162,12 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
                format_free(ft);
        }
 
+       if (fd != -1)
+               close(fd);
        return (CMD_RETURN_NORMAL);
+
+error:
+       if (fd != -1)
+               close(fd);
+       return (CMD_RETURN_ERROR);
 }
diff --git a/cmd-queue.c b/cmd-queue.c
index 7feb25e..c5905bd 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -283,27 +283,3 @@ cmdq_flush(struct cmd_q *cmdq)
        }
        cmdq->item = NULL;
 }
-
-/* Get default path using command queue. */
-const char *
-cmdq_default_path(struct cmd_q *cmdq, const char *cwd)
-{
-       struct client   *c = cmdq->client;
-       struct session  *s;
-       const char      *current;
-
-       if ((s = cmd_current_session(cmdq, 0)) == NULL)
-               return (NULL);
-
-       if (cwd == NULL)
-               cwd = options_get_string(&s->options, "default-path");
-
-       if (c != NULL && c->session == NULL && c->cwd != NULL)
-               current = c->cwd;
-       else if (s->curw != NULL)
-               current = osdep_get_cwd(s->curw->window->active->fd);
-       else
-               current = NULL;
-
-       return (cmd_default_path(s->cwd, current, cwd));
-}
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index c6c5401..3788fc2 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -20,8 +20,10 @@
 #include <sys/stat.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "tmux.h"
 
@@ -53,17 +55,14 @@ enum cmd_retval
 cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 {
        struct args             *args = self->args;
-       struct client           *c;
+       struct client           *c = cmdq->client;
        struct session          *s;
        struct paste_buffer     *pb;
-       const char              *path, *newpath, *wd;
-       char                    *cause, *start, *end;
-       size_t                   size, used;
-       int                      buffer;
-       mode_t                   mask;
+       const char              *path;
+       char                    *cause, *start, *end, *msg;
+       size_t                   size, used, msglen;
+       int                      cwd, fd, buffer;
        FILE                    *f;
-       char                    *msg;
-       size_t                   msglen;
 
        if (!args_has(args, 'b')) {
                if ((pb = paste_get_top(&global_buffers)) == NULL) {
@@ -90,7 +89,6 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
        else
                path = args->argv[0];
        if (strcmp(path, "-") == 0) {
-               c = cmdq->client;
                if (c == NULL) {
                        cmdq_error(cmdq, "can't write to stdout");
                        return (CMD_RETURN_ERROR);
@@ -100,28 +98,26 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
                goto do_print;
        }
 
-       c = cmdq->client;
-       if (c != NULL)
-               wd = c->cwd;
-       else if ((s = cmd_current_session(cmdq, 0)) != NULL) {
-               wd = options_get_string(&s->options, "default-path");
-               if (*wd == '\0')
-                       wd = s->cwd;
-       } else
-               wd = NULL;
-       if (wd != NULL && *wd != '\0') {
-               newpath = get_full_path(wd, path);
-               if (newpath != NULL)
-                       path = newpath;
-       }
-
-       mask = umask(S_IRWXG | S_IRWXO);
-       if (args_has(self->args, 'a'))
-               f = fopen(path, "ab");
+       if (c != NULL && c->session == NULL)
+               cwd = c->cwd;
+       else if ((s = cmd_current_session(cmdq, 0)) != NULL)
+               cwd = s->cwd;
        else
-               f = fopen(path, "wb");
-       umask(mask);
+               cwd = AT_FDCWD;
+
+       f = NULL;
+       if (args_has(self->args, 'a')) {
+               fd = openat(cwd, path, O_CREAT|O_RDWR|O_APPEND, 0600);
+               if (fd != -1)
+                       f = fdopen(fd, "ab");
+       } else {
+               fd = openat(cwd, path, O_CREAT|O_RDWR, 0600);
+               if (fd != -1)
+                       f = fdopen(fd, "wb");
+       }
        if (f == NULL) {
+               if (fd != -1)
+                       close(fd);
                cmdq_error(cmdq, "%s: %s", path, strerror(errno));
                return (CMD_RETURN_ERROR);
        }
diff --git a/cmd-split-window.c b/cmd-split-window.c
index a240325..ef1d3cb 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -18,7 +18,10 @@
 
 #include <sys/types.h>
 
+#include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include "tmux.h"
@@ -57,16 +60,14 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
        struct window           *w;
        struct window_pane      *wp, *new_wp = NULL;
        struct environ           env;
-       const char              *cmd, *cwd, *shell;
-       char                    *cause, *new_cause;
+       const char              *cmd, *shell, *template;
+       char                    *cause, *new_cause, *cp;
        u_int                    hlimit;
-       int                      size, percentage;
+       int                      size, percentage, cwd, fd = -1;
        enum layout_type         type;
        struct layout_cell      *lc;
-       const char              *template;
        struct client           *c;
        struct format_tree      *ft;
-       char                    *cp;
 
        if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
                return (CMD_RETURN_ERROR);
@@ -82,7 +83,29 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
                cmd = options_get_string(&s->options, "default-command");
        else
                cmd = args->argv[0];
-       cwd = cmdq_default_path(cmdq, args_get(args, 'c'));
+
+       if (args_has(args, 'c')) {
+               ft = format_create();
+               if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
+                       format_client(ft, c);
+               format_session(ft, s);
+               format_winlink(ft, s, s->curw);
+               format_window_pane(ft, s->curw->window->active);
+               cp = format_expand(ft, args_get(args, 'c'));
+               format_free(ft);
+
+               fd = open(cp, O_RDONLY|O_DIRECTORY);
+               free(cp);
+               if (fd == -1) {
+                       cmdq_error(cmdq, "bad working directory: %s",
+                           strerror(errno));
+                       return (CMD_RETURN_ERROR);
+               }
+               cwd = fd;
+       } else if (cmdq->client->session == NULL)
+               cwd = cmdq->client->cwd;
+       else
+               cwd = s->cwd;
 
        type = LAYOUT_TOPBOTTOM;
        if (args_has(args, 'h'))
@@ -155,6 +178,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
                format_free(ft);
        }
        notify_window_layout_changed(w);
+
+       if (fd != -1)
+               close(fd);
        return (CMD_RETURN_NORMAL);
 
 error:
@@ -163,5 +189,7 @@ error:
                window_remove_pane(w, new_wp);
        cmdq_error(cmdq, "create pane failed: %s", cause);
        free(cause);
+       if (fd != -1)
+               close(fd);
        return (CMD_RETURN_ERROR);
 }
diff --git a/format.c b/format.c
index ba4b95b..a7f1fde 100644
--- a/format.c
+++ b/format.c
@@ -403,7 +403,6 @@ format_client(struct format_tree *ft, struct client *c)
        time_t           t;
        struct session  *s;
 
-       format_add(ft, "client_cwd", "%s", c->cwd);
        format_add(ft, "client_height", "%u", c->tty.sy);
        format_add(ft, "client_width", "%u", c->tty.sx);
        if (c->tty.path != NULL)
@@ -552,8 +551,6 @@ format_window_pane(struct format_tree *ft, struct 
window_pane *wp)
        format_add(ft, "pane_pid", "%ld", (long) wp->pid);
        if (wp->cmd != NULL)
                format_add(ft, "pane_start_command", "%s", wp->cmd);
-       if (wp->cwd != NULL)
-               format_add(ft, "pane_start_path", "%s", wp->cwd);
        if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
                format_add(ft, "pane_current_path", "%s", cwd);
        if ((cmd = format_get_command(wp)) != NULL) {
diff --git a/options-table.c b/options-table.c
index f6a1547..5da095b 100644
--- a/options-table.c
+++ b/options-table.c
@@ -125,11 +125,6 @@ const struct options_table_entry session_options_table[] = 
{
          .default_str = ""
        },
 
-       { .name = "default-path",
-         .type = OPTIONS_TABLE_STRING,
-         .default_str = ""
-       },
-
        { .name = "default-shell",
          .type = OPTIONS_TABLE_STRING,
          .default_str = _PATH_BSHELL
diff --git a/server-client.c b/server-client.c
index 11f1937..8a99367 100644
--- a/server-client.c
+++ b/server-client.c
@@ -41,8 +41,7 @@ int   server_client_assume_paste(struct session *);
 
 int    server_client_msg_dispatch(struct client *);
 void   server_client_msg_command(struct client *, struct imsg *);
-void   server_client_msg_identify(
-           struct client *, struct msg_identify_data *, int);
+void   server_client_msg_identify(struct client *, struct imsg *);
 void   server_client_msg_shell(struct client *);
 
 /* Create a new client. */
@@ -151,6 +150,8 @@ server_client_lost(struct client *c)
         */
        if (c->flags & CLIENT_TERMINAL)
                tty_free(&c->tty);
+       free(c->ttyname);
+       free(c->term);
 
        evbuffer_free (c->stdin_data);
        evbuffer_free (c->stdout_data);
@@ -162,6 +163,7 @@ server_client_lost(struct client *c)
        screen_free(&c->status);
 
        free(c->title);
+       close(c->cwd);
 
        evtimer_del(&c->repeat_timer);
 
@@ -179,7 +181,6 @@ server_client_lost(struct client *c)
 
        free(c->prompt_string);
        free(c->prompt_buffer);
-       free(c->cwd);
 
        c->cmdq->dead = 1;
        cmdq_free(c->cmdq);
@@ -786,8 +787,6 @@ int
 server_client_msg_dispatch(struct client *c)
 {
        struct imsg              imsg;
-       struct msg_identify_data identifydata;
-       struct msg_environ_data  environdata;
        struct msg_stdin_data    stdindata;
        const char              *data;
        ssize_t                  n, datalen;
@@ -813,14 +812,14 @@ server_client_msg_dispatch(struct client *c)
 
                log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
                switch (imsg.hdr.type) {
-               case MSG_IDENTIFY:
-                       if (datalen != sizeof identifydata)
-                               fatalx("bad MSG_IDENTIFY size");
-                       memcpy(&identifydata, imsg.data, sizeof identifydata);
-#ifdef __CYGWIN__
-                       imsg.fd = open(identifydata.ttyname, O_RDWR|O_NOCTTY);
-#endif
-                       server_client_msg_identify(c, &identifydata, imsg.fd);
+               case MSG_IDENTIFY_FLAGS:
+               case MSG_IDENTIFY_TERM:
+               case MSG_IDENTIFY_TTYNAME:
+               case MSG_IDENTIFY_CWD:
+               case MSG_IDENTIFY_STDIN:
+               case MSG_IDENTIFY_ENVIRON:
+               case MSG_IDENTIFY_DONE:
+                       server_client_msg_identify(c, &imsg);
                        break;
                case MSG_COMMAND:
                        server_client_msg_command(c, &imsg);
@@ -878,23 +877,12 @@ server_client_msg_dispatch(struct client *c)
                        server_redraw_client(c);
                        recalculate_sizes();
                        break;
-               case MSG_ENVIRON:
-                       if (datalen != sizeof environdata)
-                               fatalx("bad MSG_ENVIRON size");
-                       memcpy(&environdata, imsg.data, sizeof environdata);
-
-                       environdata.var[(sizeof environdata.var) - 1] = '\0';
-                       if (strchr(environdata.var, '=') != NULL)
-                               environ_put(&c->environ, environdata.var);
-                       break;
                case MSG_SHELL:
                        if (datalen != 0)
                                fatalx("bad MSG_SHELL size");
 
                        server_client_msg_shell(c);
                        break;
-               default:
-                       fatalx("unexpected message");
                }
 
                imsg_free(&imsg);
@@ -953,46 +941,99 @@ error:
 
 /* Handle identify message. */
 void
-server_client_msg_identify(
-    struct client *c, struct msg_identify_data *data, int fd)
+server_client_msg_identify(struct client *c, struct imsg *imsg)
 {
-       c->cwd = NULL;
-       data->cwd[(sizeof data->cwd) - 1] = '\0';
-       if (*data->cwd != '\0')
-               c->cwd = xstrdup(data->cwd);
+       const char      *data;
+       size_t           datalen;
+       int              flags;
+
+       if (c->flags & CLIENT_IDENTIFIED)
+               fatalx("out-of-order identify message");
+
+       data = imsg->data;
+       datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+
+       switch (imsg->hdr.type) {
+       case MSG_IDENTIFY_FLAGS:
+               if (datalen != sizeof flags)
+                       fatalx("bad MSG_IDENTIFY_FLAGS size");
+               memcpy(&flags, data, sizeof flags);
+               c->flags |= flags;
+               break;
+       case MSG_IDENTIFY_TERM:
+               if (data[datalen - 1] != '\0')
+                       fatalx("bad MSG_IDENTIFY_TERM string");
+               c->term = xstrdup(data);
+               break;
+       case MSG_IDENTIFY_TTYNAME:
+               if (data[datalen - 1] != '\0')
+                       fatalx("bad MSG_IDENTIFY_TTYNAME string");
+               c->ttyname = xstrdup(data);
+               break;
+       case MSG_IDENTIFY_CWD:
+               if (datalen != 0)
+                       fatalx("bad MSG_IDENTIFY_CWD size");
+               c->cwd = imsg->fd;
+               break;
+       case MSG_IDENTIFY_STDIN:
+               if (datalen != 0)
+                       fatalx("bad MSG_IDENTIFY_STDIN size");
+               c->fd = imsg->fd;
+               break;
+       case MSG_IDENTIFY_ENVIRON:
+               if (data[datalen - 1] != '\0')
+                       fatalx("bad MSG_IDENTIFY_ENVIRON string");
+               if (strchr(data, '=') != NULL)
+                       environ_put(&c->environ, data);
+               break;
+       default:
+               break;
+       }
+
+       if (imsg->hdr.type != MSG_IDENTIFY_DONE)
+               return;
+       c->flags |= CLIENT_IDENTIFIED;
 
-       if (data->flags & CLIENT_CONTROL) {
+#ifdef __CYGWIN__
+       c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
+       c->cwd = open(".", O_RDONLY);
+#endif
+
+       if (c->flags & CLIENT_CONTROL) {
                c->stdin_callback = control_callback;
+
                evbuffer_free(c->stderr_data);
                c->stderr_data = c->stdout_data;
-               c->flags |= CLIENT_CONTROL;
-               if (data->flags & CLIENT_CONTROLCONTROL)
+
+               if (c->flags & CLIENT_CONTROLCONTROL)
                        evbuffer_add_printf(c->stdout_data, "\033P1000p");
                server_write_client(c, MSG_STDIN, NULL, 0);
 
                c->tty.fd = -1;
                c->tty.log_fd = -1;
 
-               close(fd);
+               close(c->fd);
+               c->fd = -1;
+
                return;
        }
 
-       if (fd == -1)
+       if (c->fd == -1)
                return;
-       if (!isatty(fd)) {
-               close(fd);
+       if (!isatty(c->fd)) {
+               close(c->fd);
+               c->fd = -1;
                return;
        }
-       data->term[(sizeof data->term) - 1] = '\0';
-       tty_init(&c->tty, c, fd, data->term);
-       if (data->flags & CLIENT_UTF8)
+       tty_init(&c->tty, c, c->fd, c->term);
+       if (c->flags & CLIENT_UTF8)
                c->tty.flags |= TTY_UTF8;
-       if (data->flags & CLIENT_256COLOURS)
+       if (c->flags & CLIENT_256COLOURS)
                c->tty.term_flags |= TERM_256COLOURS;
 
        tty_resize(&c->tty);
 
-       if (!(data->flags & CLIENT_CONTROL))
+       if (!(c->flags & CLIENT_CONTROL))
                c->flags |= CLIENT_TERMINAL;
 }
 
diff --git a/server-fn.c b/server-fn.c
index 1b49985..4fc4eb5 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -56,8 +56,8 @@ server_write_ready(struct client *c)
 }
 
 int
-server_write_client(
-    struct client *c, enum msgtype type, const void *buf, size_t len)
+server_write_client(struct client *c, enum msgtype type, const void *buf,
+    size_t len)
 {
        struct imsgbuf  *ibuf = &c->ibuf;
        int              error;
@@ -73,8 +73,8 @@ server_write_client(
 }
 
 void
-server_write_session(
-    struct session *s, enum msgtype type, const void *buf, size_t len)
+server_write_session(struct session *s, enum msgtype type, const void *buf,
+    size_t len)
 {
        struct client   *c;
        u_int            i;
diff --git a/session.c b/session.c
index bb742d8..66a52bc 100644
--- a/session.c
+++ b/session.c
@@ -84,9 +84,8 @@ session_find_by_id(u_int id)
 
 /* Create a new session. */
 struct session *
-session_create(const char *name, const char *cmd, const char *cwd,
-    struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy,
-    char **cause)
+session_create(const char *name, const char *cmd, int cwd, struct environ *env,
+    struct termios *tio, int idx, u_int sx, u_int sy, char **cause)
 {
        struct session  *s;
 
@@ -98,7 +97,7 @@ session_create(const char *name, const char *cmd, const char 
*cwd,
                fatal("gettimeofday failed");
        session_update_activity(s);
 
-       s->cwd = xstrdup(cwd);
+       s->cwd = dup(cwd);
 
        s->curw = NULL;
        TAILQ_INIT(&s->lastw);
@@ -170,7 +169,7 @@ session_destroy(struct session *s)
                winlink_remove(&s->windows, wl);
        }
 
-       free(s->cwd);
+       close(s->cwd);
 
        RB_INSERT(sessions, &dead_sessions, s);
 }
@@ -226,8 +225,8 @@ session_previous_session(struct session *s)
 
 /* Create a new window on a session. */
 struct winlink *
-session_new(struct session *s,
-    const char *name, const char *cmd, const char *cwd, int idx, char **cause)
+session_new(struct session *s, const char *name, const char *cmd, int cwd,
+    int idx, char **cause)
 {
        struct window   *w;
        struct winlink  *wl;
@@ -250,8 +249,8 @@ session_new(struct session *s,
                shell = _PATH_BSHELL;
 
        hlimit = options_get_number(&s->options, "history-limit");
-       w = window_create(
-           name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, hlimit, cause);
+       w = window_create(name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy,
+           hlimit, cause);
        if (w == NULL) {
                winlink_remove(&s->windows, wl);
                environ_free(&env);
diff --git a/tmux.1 b/tmux.1
index ba5fe18..07eb93f 100644
--- a/tmux.1
+++ b/tmux.1
@@ -568,6 +568,7 @@ The following commands are available to manage clients and 
sessions:
 .Bl -tag -width Ds
 .It Xo Ic attach-session
 .Op Fl dr
+.Op Fl c Ar working-directory
 .Op Fl t Ar target-session
 .Xc
 .D1 (alias: Ic attach )
@@ -601,6 +602,10 @@ needs to select the most recently used session, it will 
prefer the most
 recently used
 .Em unattached
 session.
+.Pp
+.Fl c
+will set the session working directory (used for new windows) to
+.Ar working-directory .
 .It Xo Ic detach-client
 .Op Fl P
 .Op Fl a
@@ -1513,13 +1518,6 @@ is not specified, the value of the
 option is used.
 .Fl c
 specifies the working directory in which the new window is created.
-It may have an absolute path or one of the following values (or a 
subdirectory):
-.Bl -column "XXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXX" -offset indent
-.It Li "Empty string" Ta "Current pane's directory"
-.It Li "~" Ta "User's home directory"
-.It Li "-" Ta "Where session was started"
-.It Li "." Ta "Where server was started"
-.El
 .Pp
 When the shell command completes, the window closes.
 See the
@@ -2179,15 +2177,6 @@ The default is an empty string, which instructs
 to create a login shell using the value of the
 .Ic default-shell
 option.
-.It Ic default-path Ar path
-Set the default working directory for new panes.
-If empty (the default), the working directory is determined from the process
-running in the active pane, from the command line environment or from the
-working directory where the session was created.
-Otherwise the same options are available as for the
-.Fl c
-flag to
-.Ic new-window .
 .It Ic default-shell Ar path
 Specify the default shell.
 This is used as the login shell for new windows when the
@@ -3056,7 +3045,6 @@ The following variables are available, where appropriate:
 .It Li "client_activity_string" Ta "" Ta "String time client last had activity"
 .It Li "client_created" Ta "" Ta "Integer time client created"
 .It Li "client_created_string" Ta "" Ta "String time client created"
-.It Li "client_cwd" Ta "" Ta "Working directory of client"
 .It Li "client_height" Ta "" Ta "Height of client"
 .It Li "client_last_session" Ta "" Ta "Name of the client's last session"
 .It Li "client_prefix" Ta "" Ta "1 if prefix key has been pressed"
diff --git a/tmux.c b/tmux.c
index 76b09cf..a035996 100644
--- a/tmux.c
+++ b/tmux.c
@@ -127,30 +127,6 @@ areshell(const char *shell)
        return (0);
 }
 
-const char *
-get_full_path(const char *wd, const char *path)
-{
-       int              fd;
-       static char      newpath[MAXPATHLEN];
-       const char      *retval;
-
-       fd = open(".", O_RDONLY);
-       if (fd == -1)
-               return (NULL);
-
-       retval = NULL;
-       if (chdir(wd) == 0) {
-               if (realpath(path, newpath) == 0)
-                       retval = newpath;
-       }
-
-       if (fchdir(fd) != 0)
-               chdir("/");
-       close(fd);
-
-       return (retval);
-}
-
 void
 parseenvironment(void)
 {
@@ -249,7 +225,7 @@ int
 main(int argc, char **argv)
 {
        struct passwd   *pw;
-       char            *s, *path, *label, *home, **var;
+       char            *s, *path, *label, *home, **var, tmp[MAXPATHLEN];
        int              opt, flags, quiet, keys;
 
 #if defined(DEBUG) && defined(__OpenBSD__)
@@ -333,6 +309,8 @@ main(int argc, char **argv)
        environ_init(&global_environ);
        for (var = environ; *var != NULL; var++)
                environ_put(&global_environ, *var);
+       if (getcwd(tmp, sizeof tmp) != NULL)
+               environ_set(&global_environ, "PWD", tmp);
 
        options_init(&global_options, NULL);
        options_table_populate_tree(server_options_table, &global_options);
diff --git a/tmux.h b/tmux.h
index 5e6de25..a76d102 100644
--- a/tmux.h
+++ b/tmux.h
@@ -52,13 +52,6 @@ extern char   **environ;
 #define NAME_INTERVAL 500
 
 /*
- * Maximum sizes of strings in message data. Don't forget to bump
- * PROTOCOL_VERSION if any of these change!
- */
-#define TERMINAL_LENGTH 128    /* length of TERM environment variable */
-#define ENVIRON_LENGTH 1024    /* environment variable length */
-
-/*
  * UTF-8 data size. This must be big enough to hold combined characters as well
  * as single.
  */
@@ -456,9 +449,6 @@ enum msgtype {
        MSG_SUSPEND,
        MSG_UNLOCK,
        MSG_WAKEUP,
-
-       MSG_IDENTIFY = 300,
-       MSG_ENVIRON
 };
 
 /*
@@ -473,21 +463,6 @@ struct msg_command_data {
        int     argc;
 }; /* followed by packed argv */
 
-struct msg_identify_data {
-       char            cwd[MAXPATHLEN];
-       char            term[TERMINAL_LENGTH];
-
-#ifdef __CYGWIN__
-       char            ttyname[TTY_NAME_MAX];
-#endif
-
-       int             flags;
-};
-
-struct msg_environ_data {
-       char            var[ENVIRON_LENGTH];
-};
-
 struct msg_stdin_data {
        ssize_t size;
        char    data[BUFSIZ];
@@ -934,7 +909,7 @@ struct window_pane {
 
        char            *cmd;
        char            *shell;
-       char            *cwd;
+       int              cwd;
 
        pid_t            pid;
        char             tty[TTY_NAME_MAX];
@@ -1081,7 +1056,7 @@ struct session {
        u_int            id;
 
        char            *name;
-       char            *cwd;
+       int              cwd;
 
        struct timeval   creation_time;
        struct timeval   activity_time;
@@ -1281,6 +1256,7 @@ RB_HEAD(status_out_tree, status_out);
 struct client {
        struct imsgbuf   ibuf;
 
+       int              fd;
        struct event     event;
        int              retval;
 
@@ -1290,8 +1266,10 @@ struct client {
        struct environ   environ;
 
        char            *title;
-       char            *cwd;
+       int              cwd;
 
+       char            *term;
+       char            *ttyname;
        struct tty       tty;
 
        void            (*stdin_callback)(struct client *, int, void *);
@@ -1524,7 +1502,6 @@ void               logfile(const char *);
 const char     *getshell(void);
 int             checkshell(const char *);
 int             areshell(const char *);
-const char*     get_full_path(const char *, const char *);
 void            setblocking(int, int);
 __dead void     shell_exec(const char *, const char *);
 
@@ -1760,7 +1737,6 @@ int                cmd_find_index(struct cmd_q *, const 
char *,
 struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **,
                     struct window_pane **);
 char           *cmd_template_replace(const char *, const char *, int);
-const char             *cmd_default_path(const char *, const char *, const 
char *);
 extern const struct cmd_entry *cmd_table[];
 extern const struct cmd_entry cmd_attach_session_entry;
 extern const struct cmd_entry cmd_bind_key_entry;
@@ -1851,7 +1827,8 @@ extern const struct cmd_entry cmd_up_pane_entry;
 extern const struct cmd_entry cmd_wait_for_entry;
 
 /* cmd-attach-session.c */
-enum cmd_retval         cmd_attach_session(struct cmd_q *, const char*, int, 
int);
+enum cmd_retval         cmd_attach_session(struct cmd_q *, const char *, int, 
int,
+                    const char *);
 
 /* cmd-list.c */
 struct cmd_list        *cmd_list_parse(int, char **, const char *, u_int, char 
**);
@@ -1869,7 +1846,6 @@ void               cmdq_run(struct cmd_q *, struct 
cmd_list *);
 void            cmdq_append(struct cmd_q *, struct cmd_list *);
 int             cmdq_continue(struct cmd_q *);
 void            cmdq_flush(struct cmd_q *);
-const char             *cmdq_default_path(struct cmd_q *, const char *);
 
 /* cmd-string.c */
 int    cmd_string_parse(const char *, struct cmd_list **, const char *,
@@ -2141,9 +2117,9 @@ void               winlink_stack_remove(struct 
winlink_stack *, struct winlink *);
 int             window_index(struct window *, u_int *);
 struct window  *window_find_by_id(u_int);
 struct window  *window_create1(u_int, u_int);
-struct window  *window_create(const char *, const char *, const char *,
-                    const char *, struct environ *, struct termios *,
-                    u_int, u_int, u_int, char **);
+struct window  *window_create(const char *, const char *, const char *, int,
+                    struct environ *, struct termios *, u_int, u_int, u_int,
+                    char **);
 void            window_destroy(struct window *);
 struct window_pane *window_get_active_at(struct window *, u_int, u_int);
 void            window_set_active_at(struct window *, u_int, u_int);
@@ -2167,8 +2143,8 @@ struct window_pane *window_pane_create(struct window *, 
u_int, u_int, u_int);
 void            window_pane_destroy(struct window_pane *);
 void            window_pane_timer_start(struct window_pane *);
 int             window_pane_spawn(struct window_pane *, const char *,
-                    const char *, const char *, struct environ *,
-                    struct termios *, char **);
+                    const char *, int, struct environ *, struct termios *,
+                    char **);
 void            window_pane_resize(struct window_pane *, u_int, u_int);
 void            window_pane_alternate_on(struct window_pane *,
                     struct grid_cell *, int);
@@ -2304,7 +2280,7 @@ RB_PROTOTYPE(sessions, session, entry, session_cmp);
 int             session_alive(struct session *);
 struct session *session_find(const char *);
 struct session *session_find_by_id(u_int);
-struct session *session_create(const char *, const char *, const char *,
+struct session *session_create(const char *, const char *, int,
                     struct environ *, struct termios *, int, u_int, u_int,
                     char **);
 void            session_destroy(struct session *);
@@ -2312,8 +2288,8 @@ int                session_check_name(const char *);
 void            session_update_activity(struct session *);
 struct session *session_next_session(struct session *);
 struct session *session_previous_session(struct session *);
-struct winlink *session_new(struct session *,
-                    const char *, const char *, const char *, int, char **);
+struct winlink *session_new(struct session *, const char *, const char *, int,
+                    int, char **);
 struct winlink *session_attach(
                     struct session *, struct window *, int, char **);
 int             session_detach(struct session *, struct winlink *);
diff --git a/window.c b/window.c
index 7912bd3..9f47f44 100644
--- a/window.c
+++ b/window.c
@@ -306,7 +306,7 @@ window_create1(u_int sx, u_int sy)
 
 struct window *
 window_create(const char *name, const char *cmd, const char *shell,
-    const char *cwd, struct environ *env, struct termios *tio,
+    int cwd, struct environ *env, struct termios *tio,
     u_int sx, u_int sy, u_int hlimit, char **cause)
 {
        struct window           *w;
@@ -672,7 +672,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, 
u_int hlimit)
 
        wp->cmd = NULL;
        wp->shell = NULL;
-       wp->cwd = NULL;
+       wp->cwd = -1;
 
        wp->fd = -1;
        wp->event = NULL;
@@ -727,7 +727,7 @@ window_pane_destroy(struct window_pane *wp)
 
        RB_REMOVE(window_pane_tree, &all_window_panes, wp);
 
-       free(wp->cwd);
+       close(wp->cwd);
        free(wp->shell);
        free(wp->cmd);
        free(wp);
@@ -735,7 +735,7 @@ window_pane_destroy(struct window_pane *wp)
 
 int
 window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
-    const char *cwd, struct environ *env, struct termios *tio, char **cause)
+    int cwd, struct environ *env, struct termios *tio, char **cause)
 {
        struct winsize   ws;
        char            *argv0, paneid[16];
@@ -754,9 +754,9 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, 
const char *shell,
                free(wp->shell);
                wp->shell = xstrdup(shell);
        }
-       if (cwd != NULL) {
-               free(wp->cwd);
-               wp->cwd = xstrdup(cwd);
+       if (cwd != -1) {
+               close(wp->cwd);
+               wp->cwd = dup(cwd);
        }
 
        log_debug("spawn: %s -- %s", wp->shell, wp->cmd);
@@ -771,7 +771,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, 
const char *shell,
                xasprintf(cause, "%s: %s", cmd, strerror(errno));
                return (-1);
        case 0:
-               if (chdir(wp->cwd) != 0)
+               if (fchdir(wp->cwd) != 0)
                        chdir("/");
 
                if (tcgetattr(STDIN_FILENO, &tio2) != 0)


-----------------------------------------------------------------------

Summary of changes:
 client.c             |   60 +++++++++---------------
 cmd-attach-session.c |   68 +++++++++++++++++++++++----
 cmd-load-buffer.c    |   30 ++++++------
 cmd-new-session.c    |   74 ++++++++++++++++++------------
 cmd-new-window.c     |   41 +++++++++++++++--
 cmd-queue.c          |   24 ----------
 cmd-save-buffer.c    |   54 ++++++++++------------
 cmd-split-window.c   |   40 ++++++++++++++--
 format.c             |    3 -
 options-table.c      |    5 --
 server-client.c      |  125 +++++++++++++++++++++++++++++++++-----------------
 server-fn.c          |    8 ++--
 session.c            |   17 +++----
 tmux.1               |   22 ++-------
 tmux.c               |   28 +----------
 tmux.h               |   56 ++++++----------------
 window.c             |   16 +++---
 17 files changed, 363 insertions(+), 308 deletions(-)


hooks/post-receive
-- 
tmux

------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60134791&iu=/4140/ostg.clktrk
_______________________________________________
tmux-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-cvs

Reply via email to