diff --git a/attach.c b/attach.c index 2de74ac..6c66ca1 100644 --- a/attach.c +++ b/attach.c @@ -203,6 +203,8 @@ static void process_kbd(int s, struct packet *pkt) else if (pkt->u.buf[0] == detach_char) { char age[32]; session_age(age, sizeof(age)); + pkt->type = MSG_DETACH; + write_packet_or_fail(s, pkt); printf("%s[%s: session '%s' detached after %s]\r\n", clear_csi_data(), progname, session_shortname(), age); exit(0); @@ -239,6 +241,10 @@ int replay_session_log(int saved_errno) { unsigned char rbuf[BUFSIZE]; ssize_t n; + struct stat st; + + if (fstat(logfd, &st) == 0 && st.st_size > SCROLLBACK_SIZE) + lseek(logfd, st.st_size - SCROLLBACK_SIZE, SEEK_SET); while ((n = read(logfd, rbuf, sizeof(rbuf))) > 0) write(1, rbuf, (size_t)n); @@ -263,10 +269,40 @@ int attach_main(int noerror) fd_set readfds; int s; + /* Attempt to open the socket. Don't display an error if noerror is + ** set. */ + s = connect_socket(sockname); + if (s < 0) { + int saved_errno = errno; + const char *name = session_shortname(); + + if (!noerror) { + if (saved_errno == ENOENT) { + printf + ("%s: session '%s' does not exist\n", + progname, name); + } else if (!replay_session_log(saved_errno)) { + if (saved_errno == ECONNREFUSED) + printf + ("%s: session '%s' is not running\n", + progname, name); + else if (saved_errno == ENOTSOCK) + printf + ("%s: '%s' is not a valid session\n", + progname, name); + else + printf("%s: %s: %s\n", progname, + sockname, strerror(saved_errno)); + } + } + return 1; + } + /* Refuse to attach to any session in our ancestry chain (catches both * direct self-attach and indirect loops like A -> B -> A). * SESSION_ENVVAR is the colon-separated chain, so scanning it covers - * all ancestors. */ + * all ancestors. The check is done after connect so that a stale env + * var from a dead session does not block new attaches. */ { const char *tosearch = getenv(SESSION_ENVVAR); @@ -281,6 +317,7 @@ int attach_main(int noerror) if (tlen == slen && strncmp(p, sockname, tlen) == 0) { + close(s); if (!noerror) printf ("%s: cannot attach to session '%s' from within itself\n", @@ -295,35 +332,6 @@ int attach_main(int noerror) } } - /* Attempt to open the socket. Don't display an error if noerror is - ** set. */ - s = connect_socket(sockname); - if (s < 0) { - int saved_errno = errno; - const char *name = session_shortname(); - - if (!noerror) { - if (!replay_session_log(saved_errno)) { - if (saved_errno == ENOENT) - printf - ("%s: session '%s' does not exist\n", - progname, name); - else if (saved_errno == ECONNREFUSED) - printf - ("%s: session '%s' is not running\n", - progname, name); - else if (saved_errno == ENOTSOCK) - printf - ("%s: '%s' is not a valid session\n", - progname, name); - else - printf("%s: %s: %s\n", progname, - sockname, strerror(saved_errno)); - } - } - return 1; - } - /* Replay the on-disk log so the user sees full session history. ** Skip if already replayed by the error path (exited-session case). */ int skip_ring = 0; @@ -373,7 +381,7 @@ int attach_main(int noerror) ** the separator: the log ends at the exact pty cursor position, so ** the prompt is already visible and correctly placed. */ if (clear_method == CLEAR_MOVE && !no_ansiterm) { - write_buf_or_fail(1, "\033c", 2); + write_buf_or_fail(1, "\033[H\033[2J\033[3J", 14); } else if (!quiet && !skip_ring) { write_buf_or_fail(1, "\r\n", 2); } diff --git a/master.c b/master.c index 16f29e3..6fbb814 100644 --- a/master.c +++ b/master.c @@ -248,28 +248,34 @@ static int create_socket(char *name) omask = umask(077); s = socket(PF_UNIX, SOCK_STREAM, 0); - umask(omask); /* umask always succeeds, errno is untouched. */ - if (s < 0) + if (s < 0) { + umask(omask); return -1; + } sockun.sun_family = AF_UNIX; memcpy(sockun.sun_path, name, strlen(name) + 1); if (bind(s, (struct sockaddr *)&sockun, sizeof(sockun)) < 0) { close(s); + umask(omask); return -1; } if (listen(s, 128) < 0) { close(s); + umask(omask); return -1; } if (setnonblocking(s) < 0) { close(s); + umask(omask); return -1; } /* chmod it to prevent any surprises */ if (chmod(name, 0600) < 0) { close(s); + umask(omask); return -1; } + umask(omask); return s; }