Compare commits

..

No commits in common. "master" and "2.2.1" have entirely different histories.

42 changed files with 314 additions and 1158 deletions

1
.github/FUNDING.yml vendored
View file

@ -1 +0,0 @@
github: nviennot

View file

@ -1,41 +0,0 @@
name: DragonflyBSD
on:
push:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/DragonflyBSD.yml'
pull_request:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/DragonflyBSD.yml'
jobs:
DragonflyBSD:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
- uses: vmactions/dragonflybsd-vm@v0
with:
prepare: |
pkg install -y automake autoconf libtool pkgconf libevent msgpack libssh gsed
usesh: true
run: |
gsed -i "s/OK/0/g" tty-term.c
autoupdate
./autogen.sh
./configure
make
make install

View file

@ -1,40 +0,0 @@
name: FreeBSD
on:
push:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/FreeBSD.yml'
pull_request:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/FreeBSD.yml'
jobs:
FreeBSD:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
- uses: vmactions/freebsd-vm@v0
with:
prepare: |
pkg install -y automake autoconf libtool pkgconf libevent msgpack libssh
usesh: true
run: |
autoupdate
./autogen.sh
./configure
make
make install

View file

@ -1,37 +0,0 @@
name: MacOS
on:
push:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/MacOS.yml'
pull_request:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/MacOS.yml'
jobs:
MacOS:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: |
brew install automake msgpack libssh
autoupdate
./autogen.sh
./configure
make
make install

View file

@ -1,40 +0,0 @@
name: NetBSD
on:
push:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/NetBSD.yml'
pull_request:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/NetBSD.yml'
jobs:
NetBSD:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
- uses: vmactions/netbsd-vm@v0
with:
prepare: |
pkg_add automake autoconf libtool pkgconf libevent msgpack libssh
usesh: true
run: |
autoupdate
./autogen.sh
./configure
make
make install

View file

@ -1,50 +0,0 @@
name: OpenBSD
on:
push:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/OpenBSD.yml'
pull_request:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/OpenBSD.yml'
jobs:
OpenBSD:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
- uses: vmactions/openbsd-vm@v0
with:
prepare: |
pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh curl
usesh: true
run: |
sed -i 's,<event.h>,<event2/event.h>,' *.[ch]
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-Makefile_am | patch
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-server_c | patch
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmate-debug_c | patch
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmate_h | patch
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmux_c | patch
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmux_h | patch
curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-osdep-openbsd_c | patch
export AUTOMAKE_VERSION=1.16
export AUTOCONF_VERSION=2.71
autoupdate
./autogen.sh
./configure
make
make install

View file

@ -1,37 +0,0 @@
name: Ubuntu
on:
push:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/Ubuntu.yml'
pull_request:
branches:
- '*'
paths:
- '**.c'
- '**.h'
- 'compat/*'
- '.github/workflows/Ubuntu.yml'
jobs:
Ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: |
sudo apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config
autoupdate
ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh
./configure
make
sudo make install

1
.gitignore vendored
View file

@ -25,4 +25,3 @@ downloads/
ext/
libssh-*/
msgpack-*/
releases/

View file

@ -1,40 +1,10 @@
language: c
services:
- docker
matrix:
include:
- arch: amd64
env: PLATFORM=amd64
- arch: amd64
env: PLATFORM=i386
- arch: arm64
env: PLATFORM=arm32v6
- arch: arm64
env: PLATFORM=arm32v7
- arch: arm64
env: PLATFORM=arm64v8
- arch: s390x
env: PLATFORM=s390x
- arch: ppc64le
env: PLATFORM=ppc64le
script:
- 'docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM'
# On arch=arm64, some directories are not setup correctly, and 'ruby -S gem
# install dpl' required by the release push scripts fails.
- 'if [ "$TRAVIS_TAG" ]; then sudo chown -R $USER: /var/lib/gems /usr/local/bin; fi'
- 'if [ "$TRAVIS_TAG" ]; then ./build_static_release.sh $TRAVIS_TAG $PLATFORM; fi'
deploy:
provider: releases
api_key:
secure: T2109tjjOsrVLEpJZK/uxmO0AuDGXYFdN4AAsNTmVwu/W5dcX57Kk2TCgqDuLfD21iGGXP0U/OYHM06IfBDODBWCA9P8ASHYsenS7wIiFnvCEMbfzoAFyBMrXN2kNdM2+ho3aqc0xE2lQKOKDLxpGm5FZrzujscXXzxQjWBU5Hk=
skip_cleanup: true
overwrite: true
file_glob: true
file: releases/*.tar.*
on:
repo: tmate-io/tmate
branch: master
tags: true
include:
- compiler: gcc
- compiler: clang
env: CFLAGS="-g -O2"
before_install:
- sudo apt-get update -qq
- sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential
script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make

View file

@ -1,37 +0,0 @@
ARG PLATFORM=amd64
FROM ${PLATFORM}/alpine:3.10 AS build
WORKDIR /build
RUN apk add --no-cache wget cmake make gcc g++ linux-headers zlib-dev openssl-dev \
automake autoconf libevent-dev ncurses-dev msgpack-c-dev libexecinfo-dev \
ncurses-static libexecinfo-static libevent-static msgpack-c ncurses-libs \
libevent libexecinfo openssl zlib
RUN set -ex; \
mkdir -p /src/libssh/build; \
cd /src; \
wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \
tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \
cd /src/libssh/build; \
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \
-DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \
-DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \
make -j $(nproc); \
make install
COPY compat ./compat
COPY *.c *.h autogen.sh Makefile.am configure.ac ./
RUN ./autogen.sh && ./configure --enable-static
RUN make -j $(nproc)
RUN objcopy --only-keep-debug tmate tmate.symbols && chmod -x tmate.symbols && strip tmate
RUN ./tmate -V
FROM alpine:3.9
RUN apk --no-cache add bash
RUN mkdir /build
ENV PATH=/build:$PATH
COPY --from=build /build/tmate.symbols /build
COPY --from=build /build/tmate /build

View file

@ -33,8 +33,8 @@ CFLAGS += -g
CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
CFLAGS += -Wundef -Wbad-function-cast -Winline
CFLAGS += -Wno-pointer-sign -Wno-attributes
CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
CPPFLAGS += -DDEBUG
endif
if IS_COVERAGE
@ -44,9 +44,6 @@ endif
CPPFLAGS += -iquote.
endif
CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-null-pointer-arithmetic
CFLAGS += -Wno-deprecated-declarations -Wno-format-nonliteral
# Set flags for Solaris.
if IS_SUNOS
if IS_GCC

61
Makefile.static-build Normal file
View file

@ -0,0 +1,61 @@
LIBSSH=libssh-0.7.2
LIBSSH_URL=https://red.libssh.org/attachments/download/177/$(LIBSSH).tar.xz
LIBSSH_LIB=ext/lib/libssh.a
MSGPACK=msgpack-1.3.0
MSGPACK_URL=https://github.com/msgpack/msgpack-c/releases/download/cpp-1.3.0/$(MSGPACK).tar.gz
MSGPACK_LIB=ext/lib/libmsgpack.a
TMATE_CONFIGURE=PKG_CONFIG_PATH=./ext/lib/pkgconfig
LIBC=$(shell gcc -print-file-name=libc.a)
STATIC_LIBC_OBJECTS=fdelt_chk
STATIC_COMPAT_OBJECTS=memcpy clock_gettime
all: tmate
dependencies:
apt-get install build-essential cmake libssl-dev autoconf automake pkg-config libtool libevent-dev libncurses-dev zlib1g-dev
downloads/$(notdir $(LIBSSH_URL)):
mkdir -p downloads
wget -O $@ $(LIBSSH_URL)
$(LIBSSH)/.ready: downloads/$(notdir $(LIBSSH_URL))
tar xf $<
touch $@
downloads/$(notdir $(MSGPACK_URL)):
mkdir -p downloads
wget -O $@ $(MSGPACK_URL)
$(MSGPACK)/.ready: downloads/$(notdir $(MSGPACK_URL))
tar xf $<
touch $@
$(LIBSSH_LIB): $(LIBSSH)/.ready
mkdir -p $(LIBSSH)/build
cd $(LIBSSH)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext .. -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF)
+make -C $(LIBSSH)/build install
$(MSGPACK_LIB): $(MSGPACK)/.ready
mkdir -p $(MSGPACK)/build
cd $(MSGPACK)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext ..)
+make -C $(MSGPACK)/build install
libc/%.o:
mkdir -p libc
cd libc; ar x $(LIBC) $(notdir $@)
compat/%.o: compat/%.c
gcc -c -o $@ $<
tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) $(patsubst %,libc/%.o,$(STATIC_LIBC_OBJECTS)) $(patsubst %,compat/%.o,$(STATIC_COMPAT_OBJECTS))
./autogen.sh
$(TMATE_CONFIGURE) ./configure --enable-static
+make
strip tmate
clean:
rm -rf ext libc $(LIBSSH) $(MSGPACK)
+make clean

View file

@ -1,33 +0,0 @@
#!/bin/bash
set -eux
# This is invoked by .travis.yml
VERSION=$1
PLATFORM=$2
SRC_VERSION=`cat configure.ac | grep AC_INIT | sed -E 's/^AC_INIT\(tmate, (.+)\)$/\1/'`
if [ $SRC_VERSION != $VERSION ]; then
echo "Version mismatch: $SRC_VERSION != $VERSION"
exit 1
fi
RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM
echo "Building $RELEASE_NAME"
docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM
mkdir -p releases
cd releases
rm -rf $RELEASE_NAME
mkdir -p $RELEASE_NAME
docker run --rm local-$PLATFORM/tmate-build cat /build/tmate > $RELEASE_NAME/tmate
chmod +x $RELEASE_NAME/tmate
tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz
rm -rf $RELEASE_NAME-symbols
mkdir -p $RELEASE_NAME-symbols
docker run --rm local-$PLATFORM/tmate-build cat /build/tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols
tar -cf - $RELEASE_NAME-symbols | xz > dbg-symbols-tmate-$VERSION-static-linux-$PLATFORM.tar.xz

37
cfg.c
View file

@ -71,7 +71,7 @@ start_cfg(void)
cfg_add_cause("%s: %s", TMUX_CONF, strerror(errno));
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmate.conf", home);
xasprintf(&cfg_file, "%s/.tmux.conf", home);
if (access(cfg_file, R_OK) != 0 && errno == ENOENT) {
free(cfg_file);
cfg_file = NULL;
@ -81,6 +81,20 @@ start_cfg(void)
cfg_add_cause("%s: %s", cfg_file, cause);
free(cause);
#ifdef TMATE
cause = NULL;
if ((home = find_home()) != NULL) {
xasprintf(&tmate_cfg_file, "%s/.tmate.conf", home);
if (access(tmate_cfg_file, R_OK) != 0 && errno == ENOENT) {
free(tmate_cfg_file);
tmate_cfg_file = NULL;
}
}
if (tmate_cfg_file != NULL && load_cfg(tmate_cfg_file, cfg_cmd_q, &cause) == -1)
cfg_add_cause("%s: %s", cfg_file, cause);
free(cause);
#endif
cmdq_continue(cfg_cmd_q);
}
@ -135,20 +149,6 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
return (found);
}
static void print_cfg_errors(void)
{
u_int i;
for (i = 0; i < cfg_ncauses; i++) {
tmate_info("%s", cfg_causes[i]);
free(cfg_causes[i]);
}
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
}
void
cfg_default_done(__unused struct cmd_q *cmdq)
{
@ -157,14 +157,7 @@ cfg_default_done(__unused struct cmd_q *cmdq)
cfg_finished = 1;
#ifdef TMATE
/* We do it this late, this way, CLI options take precedence over cfg file */
tmate_load_cli_options();
tmate_session_start();
if (tmate_foreground && cfg_ncauses) {
print_cfg_errors();
exit(1);
}
#endif
if (!RB_EMPTY(&sessions))

View file

@ -32,7 +32,6 @@
#include <unistd.h>
#include "tmux.h"
#include "tmate.h"
struct tmuxproc *client_proc;
struct tmuxpeer *client_peer;
@ -214,67 +213,8 @@ client_exit_message(void)
#ifdef TMATE
extern const struct cmd_entry cmd_attach_session_entry;
extern const struct cmd_entry cmd_new_session_entry;
/* For foreground mode */
static int __argc;
static const char **__argv;
#endif
int run_headless_command(int argc, const char **argv, int flags, void (*err_callback)(const char *))
{
struct cmd_q *cmd_q;
struct cmd_list *cmdlist;
char *cause;
cmd_q = cmdq_new(NULL); /* No client */
if ((cmdlist = cmd_list_parse(argc, (char **)argv, NULL, 0, &cause)) == NULL) {
if (err_callback)
err_callback(cause);
return -1;
}
cmdq_run(cmd_q, cmdlist, NULL);
cmd_list_free(cmdlist);
cmdq_free(cmd_q);
if (flags & DEFER_ERRORS_CFG)
return 0;
/* error messages land in cfg_causes */
int ret = cfg_ncauses ? -1 : 0;
for (u_int i = 0; i < cfg_ncauses; i++) {
if (err_callback)
err_callback(cfg_causes[i]);
free(cfg_causes[i]);
}
free(cfg_causes);
cfg_causes = NULL;
cfg_ncauses = 0;
return ret;
}
static void initial_client_cmd_err_callback(const char *cause)
{
tmate_info("%s", cause);
}
void run_initial_client_cmd(void)
{
int argc = __argc;
const char **argv = __argv;
const char *default_argv[] = {"new-session"};
if (argc == 0) {
argc = 1;
argv = default_argv;
}
if (run_headless_command(argc, argv, 0, initial_client_cmd_err_callback) < 0)
exit(1);
}
/* Client main loop. */
int
client_main(struct event_base *base, int argc, char **argv, int flags,
@ -292,8 +232,6 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
size_t size;
#ifdef TMATE
int cant_nest = 0;
__argc = argc;
__argv = (const char **)argv;
#endif
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */

View file

@ -131,9 +131,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
if (c == NULL)
detached = 1;
if (tmate_foreground)
detached = 1;
/* Is this client already attached? */
already_attached = 0;
if (c != NULL && c->session != NULL)

View file

@ -307,10 +307,6 @@ cmd_string_variable(const char *s, size_t *p)
free(buf);
if (envent == NULL)
return (xstrdup(""));
#ifdef TMATE
if (envent->value == NULL)
return (xstrdup(""));
#endif
return (xstrdup(envent->value));
error:

View file

@ -52,8 +52,6 @@
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#define Assert(Cond) if (!(Cond)) abort()
static const char Base64[] =
@ -124,7 +122,7 @@ static const char Pad64 = '=';
*/
int
b64_ntop(const char *src, size_t srclength, char *target, size_t targsize) {
b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
size_t datalength = 0;
uint8_t input[3];
uint8_t output[4];

9
compat/clock_gettime.c Normal file
View file

@ -0,0 +1,9 @@
#define _GNU_SOURCE
#include <time.h>
#include <unistd.h>
#include <sys/syscall.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
return syscall(SYS_clock_gettime, clk_id, tp);
}

11
compat/memcpy.c Normal file
View file

@ -0,0 +1,11 @@
// http://stackoverflow.com/questions/8823267/linking-against-older-symbol-version-in-a-so-file
#include <string.h>
/* some systems do not have newest memcpy@@GLIBC_2.14 - stay with old good one */
asm (".symver memcpy, memcpy@GLIBC_2.2.5");
void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
return memcpy(dest, src, n);
}

View file

@ -1,8 +1,7 @@
# configure.ac
AC_INIT(tmate, 2.4.0)
AC_INIT(tmate, 2.2.1)
AM_SILENT_RULES([yes])
AC_CONFIG_AUX_DIR(etc)
AM_INIT_AUTOMAKE([foreign subdir-objects])
@ -48,11 +47,10 @@ AC_ARG_ENABLE(
found_static=$enable_static
)
if test "x$found_static" = xyes; then
# XXX Static build are only doable with the musl library
PKG_CONFIG="pkg-config --static"
CFLAGS="$CFLAGS -flto"
LDFLAGS="$LDFLAGS -flto -static -no-pie"
LDFLAGS="$LDFLAGS -flto"
PKG_CHECK_MODULES([ZLIB], [zlib], [
CPPFLAGS="$ZLIB_CFLAGS $CPPFLAGS"
@ -63,6 +61,7 @@ if test "x$found_static" = xyes; then
CPPFLAGS="$LIBCRYPTO_CFLAGS $CPPFLAGS"
LIBS="$LIBCRYPTO_LIBS $LIBS"
])
# See more static settings below... (search for found_static)
fi
# Is this gcc?
@ -103,7 +102,6 @@ AC_CHECK_HEADERS(
bitstring.h \
curses.h \
dirent.h \
execinfo.h \
fcntl.h \
inttypes.h \
libutil.h \
@ -123,13 +121,9 @@ AC_CHECK_HEADERS(
# Look for library needed for flock.
AC_SEARCH_LIBS(flock, bsd)
# Look for library needed for backtrace
AC_SEARCH_LIBS(backtrace, execinfo)
# Check for some functions that are replaced or omitted.
AC_CHECK_FUNCS(
[ \
backtrace \
dirfd \
flock \
setproctitle \
@ -215,7 +209,7 @@ fi
PKG_CHECK_MODULES(
LIBSSH,
libssh >= 0.8.4,
libssh >= 0.6.0,
[
CPPFLAGS="$LIBSSH_CFLAGS $CPPFLAGS"
LIBS="$LIBSSH_LIBS $LIBS"
@ -224,7 +218,7 @@ PKG_CHECK_MODULES(
found_libssh=no
)
if test "x$found_libssh" = xno; then
AC_MSG_ERROR("libssh >= 0.8.4 not found")
AC_MSG_ERROR("libssh >= 0.6.0 not found")
fi
# Check for b64_ntop.
@ -463,6 +457,17 @@ if test "x$found_getopt" != xno; then
fi
AM_CONDITIONAL(NO_GETOPT, [test "x$found_getopt" = xno])
if test "x$found_static" = xyes; then
# libc and libdl should be dynamically linked.
# but we want to lower our requirements for libc's version.
# so we extract some symobls and add them here
if test `uname -m` = x86_64; then
LIBS="compat/memcpy.o -Wl,--wrap=memcpy $LIBS"
fi
LIBS="compat/clock_gettime.o libc/fdelt_chk.o $LIBS"
LIBS="-Wl,-Bstatic ${LIBS/-ldl/} -Wl,-Bdynamic -ldl"
fi
# Check for BSD-style integer types.
AC_MSG_CHECKING(for BSD-style unsigned types)
AC_COMPILE_IFELSE([AC_LANG_SOURCE(

61
log.c
View file

@ -32,11 +32,6 @@ static int log_level;
static void log_event_cb(int, const char *);
static void log_vwrite(const char *, va_list);
static int is_log_stdout(void)
{
return fileno(log_file) <= 2;
}
/* Log callback for libevent. */
static void
log_event_cb(__unused int severity, const char *msg)
@ -58,21 +53,6 @@ log_get_level(void)
return (log_level);
}
void
log_open_fp(FILE *f)
{
if (log_file == f)
return;
if (log_file != NULL && !is_log_stdout())
fclose(log_file);
log_file = f;
setvbuf(log_file, NULL, _IOLBF, 0);
event_set_log_callback(log_event_cb);
}
/* Open logging to file. */
void
log_open(const char *name)
@ -82,18 +62,24 @@ log_open(const char *name)
if (log_level == 0)
return;
if (log_file != NULL)
fclose(log_file);
xasprintf(&path, "tmate-%s-%ld.log", name, (long)getpid());
FILE *f = fopen(path, "w");
log_file = fopen(path, "w");
free(path);
if (f)
log_open_fp(f);
if (log_file == NULL)
return;
setvbuf(log_file, NULL, _IOLBF, 0);
event_set_log_callback(log_event_cb);
}
/* Close logging. */
void
log_close(void)
{
if (log_file != NULL && !is_log_stdout())
if (log_file != NULL)
fclose(log_file);
log_file = NULL;
@ -101,7 +87,6 @@ log_close(void)
}
/* Write a log message. */
__attribute__((__format__(__printf__, 1, 0)))
static void
log_vwrite(const char *msg, va_list ap)
{
@ -117,16 +102,9 @@ log_vwrite(const char *msg, va_list ap)
exit(1);
gettimeofday(&tv, NULL);
if (is_log_stdout()) {
if (fprintf(log_file, "%s\n", out) == -1)
exit(1);
} else {
if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
(int)tv.tv_usec, out) == -1)
exit(1);
}
if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
(int)tv.tv_usec, out) == -1)
exit(1);
fflush(log_file);
free(out);
@ -135,20 +113,16 @@ log_vwrite(const char *msg, va_list ap)
/* Log a debug message. */
void
log_emit(int level, const char *msg, ...)
log_debug(const char *msg, ...)
{
va_list ap;
if (log_level < level)
return;
va_start(ap, msg);
log_vwrite(msg, ap);
va_end(ap);
}
/* Log a critical error with error string and die. */
__attribute__((__format__(__printf__, 1, 0)))
__dead void
fatal(const char *msg, ...)
{
@ -158,13 +132,11 @@ fatal(const char *msg, ...)
va_start(ap, msg);
if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
exit(1);
msg = fmt;
log_vwrite(msg, ap);
log_vwrite(fmt, ap);
exit(1);
}
/* Log a critical error and die. */
__attribute__((__format__(__printf__, 1, 0)))
__dead void
fatalx(const char *msg, ...)
{
@ -174,7 +146,6 @@ fatalx(const char *msg, ...)
va_start(ap, msg);
if (asprintf(&fmt, "fatal: %s", msg) == -1)
exit(1);
msg = fmt;
log_vwrite(msg, ap);
log_vwrite(fmt, ap);
exit(1);
}

View file

@ -925,19 +925,13 @@ const struct options_table_entry options_table[] = {
{ .name = "tmate-server-rsa-fingerprint",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = "SHA256:Hthk2T/M/Ivqfk1YYUn5ijC2Att3+UPzD7Rn72P5VWs"
.default_str = "af:2d:81:c1:fe:49:70:2d:7f:09:a9:d7:4b:32:e3:be"
},
{ .name = "tmate-server-ecdsa-fingerprint",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = "SHA256:8GmKHYHEJ6n0TEdciHeEGkKOigQfCFuBULdt6vZIhDc"
},
{ .name = "tmate-server-ed25519-fingerprint",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = "SHA256:jfttvoypkHiQYUqUCwKeqd9d1fJj/ZiQlFOHVl6E9sI"
.default_str = "c7:a1:51:36:d2:bb:35:4b:0a:1a:c0:43:97:74:ea:42"
},
{ .name = "tmate-display-time",
@ -959,44 +953,6 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
},
{ .name = "tmate-api-key",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
},
{ .name = "tmate-session-name",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
},
{ .name = "tmate-session-name-ro",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
},
{ .name = "tmate-authorized-keys",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
},
{ .name = "tmate-set",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
},
{ .name = "tmate-foreground-restart",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
.minimum = 0,
.maximum = 1,
.default_num = 1
},
#endif
{ .name = NULL }

View file

@ -28,9 +28,7 @@ char *osdep_get_name(int, char *);
char *osdep_get_cwd(int);
struct event_base *osdep_event_init(void);
#ifndef __unused
#define __unused __attribute__ ((__unused__))
#endif
char *
osdep_get_name(int fd, __unused char *tty)

10
proc.c
View file

@ -172,7 +172,7 @@ proc_start(const char *name, struct event_base *base, int forkflag,
struct tmuxproc *tp;
struct utsname u;
if (forkflag && !tmate_foreground) {
if (forkflag) {
switch (fork()) {
case -1:
fatal("fork failed");
@ -189,13 +189,7 @@ proc_start(const char *name, struct event_base *base, int forkflag,
fatalx("event_reinit failed");
}
if (tmate_foreground) {
if (forkflag)
clear_signals(0);
log_open_fp(stdout);
} else {
log_open(name);
}
log_open(name);
#ifdef HAVE_SETPROCTITLE
setproctitle("%s (%s)", name, socket_path);

View file

@ -278,7 +278,7 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top)
struct window *w = s->curw->window;
struct options *oo = w->options;
struct tty *tty = &c->tty;
struct window_pane *wp = NULL;
struct window_pane *wp;
struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
struct grid_cell msg_gc;
u_int i, j, type, msgx = 0, msgy = 0;

View file

@ -152,16 +152,14 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
{
int pair[2];
if (!tmate_foreground)
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
server_proc = proc_start("server", base, 1, server_signal);
if (server_proc == NULL) {
close(pair[1]);
return (pair[0]);
}
close(pair[0]);
if (log_get_level() > 3)
@ -192,8 +190,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
if (server_fd == -1)
fatal("couldn't create socket");
server_update_socket();
if (!tmate_foreground)
server_client_create(pair[1]);
server_client_create(pair[1]);
if (lockfd >= 0) {
unlink(lockfile);
@ -208,17 +205,17 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
status_prompt_load_history();
server_add_accept(0);
#ifdef TMATE
tmate_write_ready();
#endif
if (tmate_foreground)
run_initial_client_cmd();
server_add_accept(0);
proc_loop(server_proc, server_loop);
status_prompt_save_history();
#ifdef TMATE
unlink(socket_path);
#endif
exit(0);
}
@ -368,7 +365,6 @@ server_signal(int sig)
int fd;
switch (sig) {
case SIGINT:
case SIGTERM:
server_exit = 1;
server_send_exit();

View file

@ -207,36 +207,6 @@ session_free(__unused int fd, __unused short events, void *arg)
}
}
static void maybe_restart_session(void)
{
int fg_restart = options_get_number(global_options, "tmate-foreground-restart");
if (!fg_restart)
return;
/*
* throttle restarts. This is a blocking sleep. It's
* simpler than using a timer, but fairly harmless
* from a blocking perspective.
*/
usleep(500*1000);
next_session_id = 0;
run_initial_client_cmd();
tmate_info("Session shell restarted");
struct session *s;
s = RB_MIN(sessions, &sessions);
if (!s)
return;
struct window_pane *wp;
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
window_copy_add(wp, "%s", "Session shell restarted");
window_copy_add(wp, "%s", "Note: press the following sequence to disconnect from SSH: <Enter>~.");
}
/* Destroy a session. */
void
session_destroy(struct session *s)
@ -245,6 +215,10 @@ session_destroy(struct session *s)
log_debug("session %s destroyed", s->name);
#ifdef TMATE
tmate_write_fin();
#endif
RB_REMOVE(sessions, &sessions, s);
notify_session_closed(s);
@ -266,15 +240,6 @@ session_destroy(struct session *s)
free((void *)s->cwd);
session_unref(s);
#ifdef TMATE
if (tmate_foreground && !server_exit) {
maybe_restart_session();
} else {
tmate_info("Session closed");
tmate_write_fin();
}
#endif
}
/* Check a session name is valid: not empty and no colons or periods. */
@ -621,7 +586,6 @@ session_group_index(struct session_group *sg)
}
fatalx("session group not found");
for(;;);
}
/*

View file

@ -24,7 +24,6 @@
#include "tmux.h"
struct event ev_sigint;
struct event ev_sighup;
struct event ev_sigchld;
struct event ev_sigcont;
@ -41,23 +40,15 @@ set_signals(void (*handler)(int, short, void *), void *arg)
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
#ifndef TMATE
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
#endif
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
#ifndef TMATE
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
#endif
#ifdef TMATE
signal_set(&ev_sigint, SIGINT, handler, arg);
signal_add(&ev_sigint, NULL);
#endif
signal_set(&ev_sighup, SIGHUP, handler, arg);
signal_add(&ev_sighup, NULL);
signal_set(&ev_sigchld, SIGCHLD, handler, arg);
@ -81,24 +72,16 @@ clear_signals(int after_fork)
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
#ifndef TMATE
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
#endif
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
#ifndef TMATE
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
#endif
if (after_fork) {
#ifdef TMATE
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
#endif
if (sigaction(SIGHUP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGCHLD, &sigact, NULL) != 0)
@ -112,7 +95,6 @@ clear_signals(int after_fork)
if (sigaction(SIGWINCH, &sigact, NULL) != 0)
fatal("sigaction failed");
} else {
event_del(&ev_sigint);
event_del(&ev_sighup);
event_del(&ev_sigchld);
event_del(&ev_sigcont);

View file

@ -1,20 +1,10 @@
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <signal.h>
#include "tmate.h"
#ifndef HAVE_BACKTRACE
void tmate_print_stack_trace(void) {}
void tmate_catch_sigsegv(void) {}
void tmate_preload_trace_lib(void) {}
#else
#if DEBUG
static int print_resolved_stack_frame(const char *frame)
@ -85,28 +75,16 @@ void tmate_print_stack_trace(void)
free (strings);
}
static void handle_crash(int sig)
static void handle_sigsegv(__unused int sig)
{
/* TODO send stack trace to server */
const char *what = sig == SIGSEGV ? "SIGSEGV" : "SIGABRT";
tmate_info("%s printing stack trace", what);
tmate_info("CRASH, printing stack trace");
tmate_print_stack_trace();
/* Reraise */
signal(sig, NULL);
kill(getpid(), sig);
tmate_fatal("CRASHED");
}
void tmate_catch_sigsegv(void)
{
signal(SIGSEGV, handle_crash);
signal(SIGABRT, handle_crash);
signal(SIGSEGV, handle_sigsegv);
}
void tmate_preload_trace_lib(void)
{
void *array[1];
backtrace(array, 1);
}
#endif

View file

@ -1,4 +1,3 @@
#include <sys/utsname.h>
#include "tmate.h"
#include "tmate-protocol.h"
#include "window-copy.h"
@ -13,23 +12,6 @@ void tmate_write_header(void)
pack(string, VERSION);
}
void tmate_write_uname(void)
{
struct utsname name;
if (uname(&name) < 0) {
tmate_debug("uname() failed");
return;
}
pack(array, 6);
pack(int, TMATE_OUT_UNAME);
pack(string, name.sysname);
pack(string, name.nodename);
pack(string, name.release);
pack(string, name.version);
pack(string, name.machine);
}
void tmate_write_ready(void)
{
pack(array, 1);
@ -256,14 +238,6 @@ void tmate_exec_cmd_args(int argc, const char **argv)
append_saved_cmd(&tmate_session, argc, argv);
}
void tmate_set_val(const char *name, const char *value)
{
char *buf;
xasprintf(&buf, "%s=%s", name, value);
tmate_exec_cmd_args(3, (const char *[]){"set-option", "tmate-set", buf});
free(buf);
}
void tmate_exec_cmd(struct cmd *cmd)
{
int argc;
@ -482,7 +456,6 @@ void tmate_send_reconnection_state(struct tmate_session *session)
tmate_send_reconnection_data(session);
replay_saved_cmd(session);
/* TODO send all option variables */
tmate_write_uname();
tmate_write_ready();
tmate_sync_layout();

View file

@ -50,39 +50,19 @@ static void tmate_status_message_client(struct client *c, const char *message)
recalculate_sizes();
}
static void tmate_status_message_session(const char *message)
{
if (tmate_foreground)
return;
struct session *s;
s = RB_MIN(sessions, &sessions);
if (!s) {
cfg_add_cause("%s", message);
return;
}
struct window_pane *wp;
wp = s->curw->window->active;
if (wp->mode == &window_copy_mode)
window_copy_add(wp, "%s", message);
}
void __tmate_status_message(const char *fmt, va_list ap)
{
struct client *c;
char *message;
xvasprintf(&message, fmt, ap);
tmate_info("%s", message);
tmate_debug("%s", message);
TAILQ_FOREACH(c, &clients, entry) {
if (c && !(c->flags & CLIENT_READONLY))
tmate_status_message_client(c, message);
}
tmate_status_message_session(message);
free(message);
}

View file

@ -19,7 +19,7 @@ static int on_encoder_write(void *userdata, const char *buf, size_t len)
tmate_fatal("Cannot buffer encoded data");
if (!encoder->ev_active) {
event_active(encoder->ev_buffer, EV_READ, 0);
event_active(&encoder->ev_buffer, EV_READ, 0);
encoder->ev_active = true;
}
@ -57,12 +57,10 @@ void tmate_encoder_init(struct tmate_encoder *encoder,
if (!encoder->buffer)
tmate_fatal("Can't allocate buffer");
encoder->ev_buffer = event_new(tmate_session.ev_base, -1,
EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder);
if (!encoder->ev_buffer)
tmate_fatal("Can't allocate event");
event_set(&encoder->ev_buffer, -1,
EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder);
event_add(encoder->ev_buffer, NULL);
event_add(&encoder->ev_buffer, NULL);
encoder->ev_active = false;
}
@ -71,8 +69,7 @@ void tmate_encoder_destroy(struct tmate_encoder *encoder)
{
/* encoder->pk doesn't need any cleanup */
evbuffer_free(encoder->buffer);
event_del(encoder->ev_buffer);
event_free(encoder->ev_buffer);
event_del(&encoder->ev_buffer);
memset(encoder, 0, sizeof(*encoder));
}

View file

@ -56,7 +56,6 @@ enum tmate_daemon_out_msg_types {
TMATE_OUT_RECONNECT,
TMATE_OUT_SNAPSHOT,
TMATE_OUT_EXEC_CMD,
TMATE_OUT_UNAME,
};
/*
@ -78,8 +77,6 @@ enum tmate_daemon_out_msg_types {
[TMATE_OUT_RECONNECT, string: reconnection_data]
[TMATE_OUT_SNAPSHOT, ...]
[TMATE_OUT_EXEC_CMD, string: cmd_name, ...string: args]
[TMATE_OUT_UNAME, string: name.sysname, string: name.nodename,
string: name.release, string: name.version, string: name.machine]
*/
enum tmate_daemon_in_msg_types {

View file

@ -2,10 +2,8 @@
#include <event2/util.h>
#include <event2/event.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -21,53 +19,35 @@ struct tmate_session tmate_session;
static void lookup_and_connect(void);
static void on_dns_retry(__unused evutil_socket_t fd, __unused short what,
void *arg)
__unused void *arg)
{
struct tmate_session *session = arg;
assert(session->ev_dns_retry);
event_free(session->ev_dns_retry);
session->ev_dns_retry = NULL;
lookup_and_connect();
}
static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr)
{
struct evutil_addrinfo *ai;
struct timeval tv;
const char *host = ptr;
evdns_base_free(tmate_session.ev_dnsbase, 0);
tmate_session.ev_dnsbase = NULL;
if (errcode) {
struct tmate_session *session = &tmate_session;
if (session->ev_dns_retry)
return;
struct timeval tv = { .tv_sec = TMATE_DNS_RETRY_TIMEOUT, .tv_usec = 0 };
session->ev_dns_retry = evtimer_new(session->ev_base, on_dns_retry, session);
if (!session->ev_dns_retry)
tmate_fatal("out of memory");
evtimer_add(session->ev_dns_retry, &tv);
tmate_status_message("%s lookup failure. Retrying in %d seconds (%s)",
host, TMATE_DNS_RETRY_TIMEOUT,
evutil_gai_strerror(errcode));
tv.tv_sec = TMATE_DNS_RETRY_TIMEOUT;
tv.tv_usec = 0;
evtimer_assign(&tmate_session.ev_dns_retry, tmate_session.ev_base,
on_dns_retry, NULL);
evtimer_add(&tmate_session.ev_dns_retry, &tv);
return;
}
tmate_status_message("Connecting to %s...", host);
int i, num_clients = 0;
for (ai = addr; ai; ai = ai->ai_next)
num_clients++;
struct tmate_ssh_client *ssh_clients[num_clients];
for (ai = addr, i = 0; ai; ai = ai->ai_next, i++) {
for (ai = addr; ai; ai = ai->ai_next) {
char buf[128];
const char *ip = NULL;
if (ai->ai_family == AF_INET) {
@ -78,13 +58,23 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr)
ip = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
}
ssh_clients[i] = tmate_ssh_client_alloc(&tmate_session, ip);
tmate_debug("Trying server %s", ip);
/*
* Note: We don't deal with the client list. Clients manage it
* and free client structs when necessary.
*/
(void)tmate_ssh_client_alloc(&tmate_session, ip);
}
for (i = 0; i < num_clients; i++)
connect_ssh_client(ssh_clients[i]);
evutil_freeaddrinfo(addr);
/*
* XXX For some reason, freeing the DNS resolver makes MacOSX flip out...
* not sure what's going on...
* evdns_base_free(tmate_session.ev_dnsbase, 0);
* tmate_session.ev_dnsbase = NULL;
*/
}
static void lookup_and_connect(void)
@ -92,8 +82,8 @@ static void lookup_and_connect(void)
struct evutil_addrinfo hints;
const char *tmate_server_host;
assert(!tmate_session.ev_dnsbase);
tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1);
if (!tmate_session.ev_dnsbase)
tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1);
if (!tmate_session.ev_dnsbase)
tmate_fatal("Cannot initialize the DNS lookup service");
@ -105,7 +95,7 @@ static void lookup_and_connect(void)
tmate_server_host = options_get_string(global_options,
"tmate-server-host");
tmate_debug("Looking up %s...", tmate_server_host);
tmate_info("Looking up %s...", tmate_server_host);
(void)evdns_getaddrinfo(tmate_session.ev_dnsbase, tmate_server_host, NULL,
&hints, dns_cb, (void *)tmate_server_host);
}
@ -138,50 +128,6 @@ void tmate_session_init(struct event_base *base)
tmate_write_header();
}
static void send_authorized_keys(void)
{
char *path;
path = options_get_string(global_options, "tmate-authorized-keys");
if (strlen(path) == 0)
return;
path = xstrdup(path);
tmate_info("Using %s for access control", path);
FILE *f;
char *line;
size_t len;
if (path[0] == '~' && path[1] == '/') {
const char *home = find_home();
if (home) {
char *new_path;
xasprintf(&new_path, "%s%s", home, &path[1]);
free(path);
path = new_path;
}
}
if ((f = fopen(path, "r")) == NULL) {
cfg_add_cause("%s: %s", path, strerror(errno));
free(path);
return;
}
while ((line = fparseln(f, &len, NULL, NULL, 0)) != NULL) {
if (len == 0)
continue;
tmate_set_val("authorized_keys", line);
free(line);
}
if (ferror(f))
cfg_add_cause("%s: %s", path, strerror(errno));
fclose(f);
free(path);
}
void tmate_session_start(void)
{
/*
@ -191,19 +137,6 @@ void tmate_session_start(void)
* - While we are parsing the config file, we need to be able to
* serialize it, and so we need a worker encoder.
*/
if (tmate_foreground) {
tmate_set_val("foreground", "true");
tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path);
} else {
cfg_add_cause("%s", "Tip: if you wish to use tmate only for remote access, run: tmate -F");
cfg_add_cause("%s", "To see the following messages again, run in a tmate session: tmate show-messages");
cfg_add_cause("%s", "Press <q> or <ctrl-c> to continue");
cfg_add_cause("%s", "---------------------------------------------------------------------");
}
send_authorized_keys();
tmate_write_uname();
tmate_write_ready();
lookup_and_connect();
}
@ -211,18 +144,12 @@ static void on_reconnect_retry(__unused evutil_socket_t fd, __unused short what,
{
struct tmate_session *session = arg;
assert(session->ev_connection_retry);
event_free(session->ev_connection_retry);
session->ev_connection_retry = NULL;
if (session->last_server_ip) {
/*
* We have a previous server ip. Let's try that again first,
* but then connect to any server if it fails again.
*/
struct tmate_ssh_client *c = tmate_ssh_client_alloc(session,
session->last_server_ip);
connect_ssh_client(c);
(void)tmate_ssh_client_alloc(&tmate_session, session->last_server_ip);
free(session->last_server_ip);
session->last_server_ip = NULL;
} else {
@ -240,21 +167,18 @@ void tmate_reconnect_session(struct tmate_session *session, const char *message)
*/
struct timeval tv = { .tv_sec = TMATE_RECONNECT_RETRY_TIMEOUT, .tv_usec = 0 };
if (session->ev_connection_retry)
return;
evtimer_assign(&session->ev_connection_retry, session->ev_base,
on_reconnect_retry, session);
evtimer_add(&session->ev_connection_retry, &tv);
session->ev_connection_retry = evtimer_new(session->ev_base, on_reconnect_retry, session);
if (!session->ev_connection_retry)
tmate_fatal("out of memory");
evtimer_add(session->ev_connection_retry, &tv);
if (message && !tmate_foreground)
if (message)
tmate_status_message("Reconnecting... (%s)", message);
else
tmate_status_message("Reconnecting...");
/*
* This says that we'll need to send a snapshot of the current state.
* Until we have persisted logs...
*/
session->reconnected = true;
}

View file

@ -1,9 +1,6 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <event.h>
#include <assert.h>
@ -87,6 +84,7 @@ static void on_ssh_auth_server_complete(struct tmate_ssh_client *connected_clien
if (client == connected_client)
continue;
assert(!client->has_encoder);
kill_ssh_client(client, NULL);
}
}
@ -115,7 +113,7 @@ static int passphrase_callback(__unused const char *prompt, char *buf, size_t le
client->tmate_session->need_passphrase = 1;
if (client->tmate_session->passphrase)
strlcpy(buf, client->tmate_session->passphrase, len);
strncpy(buf, client->tmate_session->passphrase, len);
else
strcpy(buf, "");
@ -167,106 +165,59 @@ static void request_passphrase(struct tmate_ssh_client *client)
data->password_cb_private = client;
}
#define KEEPALIVE_IDLE 30
#define KEEPALIVE_CNT 4
#define KEEPALIVE_INTVL 11
#define WRITE_TIMEOUT 80
static void tune_socket_opts(int fd)
{
#define SSO(level, optname, val) ({ \
int _flag = val; \
if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \
/* If the connection has been closed, we'll get EINVAL */ \
if (errno != EINVAL) \
tmate_info("setsockopt(" #level ", " #optname ", %d) failed %s", val, strerror(errno)); \
} \
})
SSO(IPPROTO_IP, IP_TOS, 0x10); /* IPTOS_LOWDELAY */
SSO(IPPROTO_TCP, TCP_NODELAY, 1);
SSO(SOL_SOCKET, SO_KEEPALIVE, 1);
#ifdef TCP_KEEPALIVE
/*
* The TCP_KEEPALIVE options enable to specify the amount of time, in
* seconds, that the connection must be idle before keepalive probes
* (if enabled) are sent.
*/
SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE);
#endif
#ifdef TCP_KEEPIDLE
/*
* Same as TCP_KEEPALIVE, but on different systems
*/
SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE);
#endif
#ifdef TCP_KEEPCNT
/*
* When keepalive probes are enabled, this option will set the number
* of times a keepalive probe should be repeated if the peer is not
* responding. After this many probes, the connection will be closed.
*/
SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT);
#endif
#ifdef TCP_KEEPINTVL
/*
* When keepalive probes are enabled, this option will set the amount
* of time in seconds between successive keepalives sent to probe an
* unresponsive peer.
*/
SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL);
#endif
#ifdef TCP_USER_TIMEOUT
/*
* This option takes an unsigned int as an argument. When the
* value is greater than 0, it specifies the maximum amount of
* time in milliseconds that transmitted data may remain
* unacknowledged before TCP will forcibly close the
* corresponding connection and return ETIMEDOUT to the
* application.
*/
SSO(IPPROTO_TCP, TCP_USER_TIMEOUT, 1000*WRITE_TIMEOUT);
#endif
#undef SSO
}
static void init_conn_fd(struct tmate_ssh_client *client)
{
int fd;
if (client->ev_ssh)
if (client->has_init_conn_fd)
return;
if ((fd = ssh_get_fd(client->session)) < 0)
if (ssh_get_fd(client->session) < 0)
return;
tune_socket_opts(fd);
{
int flag = 1;
setsockopt(ssh_get_fd(client->session), IPPROTO_TCP,
TCP_NODELAY, &flag, sizeof(flag));
}
client->ev_ssh = event_new(client->tmate_session->ev_base, fd,
EV_READ | EV_PERSIST,
__on_ssh_client_event, client);
if (!client->ev_ssh)
tmate_fatal("out of memory");
event_add(client->ev_ssh, NULL);
event_set(&client->ev_ssh, ssh_get_fd(client->session),
EV_READ | EV_PERSIST, __on_ssh_client_event, client);
event_add(&client->ev_ssh, NULL);
client->has_init_conn_fd = true;
}
static void on_ssh_client_event(struct tmate_ssh_client *client)
{
char *identity;
ssh_key pubkey;
int key_type;
unsigned char *hash;
ssize_t hash_len;
char *hash_str;
const char *server_hash_str;
int match;
int verbosity = SSH_LOG_NOLOG + log_get_level();
int port = options_get_number(global_options, "tmate-server-port");
ssh_session session = client->session;
ssh_channel channel = client->channel;
switch (client->state) {
case SSH_INIT: {
case SSH_INIT:
client->session = session = ssh_new();
if (!session) {
tmate_fatal("cannot ssh_new()");
tmate_fatal("cannot initialize");
return;
}
ssh_set_callbacks(session, &client->ssh_callbacks);
int verbosity = SSH_LOG_NOLOG + log_get_level();
int port = options_get_number(global_options, "tmate-server-port");
client->channel = channel = ssh_channel_new(session);
if (!channel) {
tmate_fatal("cannot initialize");
return;
}
ssh_set_blocking(session, 0);
ssh_options_set(session, SSH_OPTIONS_HOST, client->server_ip);
@ -275,7 +226,6 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
ssh_options_set(session, SSH_OPTIONS_USER, "tmate");
ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes");
char *identity;
if ((identity = get_identity())) {
/*
* FIXME libssh will continue with the next set of
@ -283,15 +233,11 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
* regular one doesn't.
*/
ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity);
/* Do not use keys from ssh-agent. */
unsetenv("SSH_AUTH_SOCK");
free(identity);
}
client->state = SSH_CONNECT;
}
// fall through
/* fall through */
case SSH_CONNECT:
switch (ssh_connect(session)) {
@ -307,34 +253,19 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
tmate_debug("Establishing connection to %s", client->server_ip);
client->state = SSH_AUTH_SERVER;
/* fall through */
}
// fall through
case SSH_AUTH_SERVER: {
ssh_key pubkey;
enum ssh_keytypes_e key_type;
unsigned char *hash;
ssize_t hash_len;
char *hash_str;
const char *server_hash_str;
int match;
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
if (ssh_get_server_publickey(session, &pubkey) < 0)
tmate_fatal("ssh_get_server_publickey");
#else
case SSH_AUTH_SERVER:
if (ssh_get_publickey(session, &pubkey) < 0)
tmate_fatal("ssh_get_publickey");
#endif
if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256,
&hash, &hash_len) < 0) {
kill_ssh_client(client, "Failed to get server fingerprint");
if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, &hash, &hash_len) < 0) {
kill_ssh_client(client, "Cannot authenticate server");
return;
}
hash_str = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256,
hash, hash_len);
hash_str = ssh_get_hexa(hash, hash_len);
if (!hash_str)
tmate_fatal("malloc failed");
@ -346,34 +277,23 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
"tmate-server-rsa-fingerprint");
break;
case SSH_KEYTYPE_ECDSA:
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521:
#endif
server_hash_str = options_get_string(global_options,
"tmate-server-ecdsa-fingerprint");
break;
case SSH_KEYTYPE_ED25519:
server_hash_str = options_get_string(global_options,
"tmate-server-ed25519-fingerprint");
break;
default:
server_hash_str = "";
}
match = !strcmp(hash_str, server_hash_str);
if (!match) {
kill_ssh_client(client, "Server fingerprint not recognized: "
"`%s', expected `%s'", server_hash_str, hash_str);
}
ssh_key_free(pubkey);
ssh_clean_pubkey_hash(&hash);
free(hash_str);
if (!match)
if (!match) {
kill_ssh_client(client, "Cannot authenticate server");
return;
}
/*
* At this point, we abort other connection attempts to the
@ -383,31 +303,13 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
*/
tmate_debug("Connected to %s", client->server_ip);
on_ssh_auth_server_complete(client);
client->state = SSH_AUTH_CLIENT;
client->state = SSH_AUTH_CLIENT_NONE;
}
// fall through
/* fall through */
case SSH_AUTH_CLIENT_NONE:
switch (ssh_userauth_none(session, NULL)) {
case SSH_AUTH_AGAIN:
return;
case SSH_AUTH_ERROR:
kill_ssh_client(client, "Auth error: %s", ssh_get_error(session));
return;
case SSH_AUTH_SUCCESS:
tmate_debug("Auth successful via none method");
client->state = SSH_NEW_CHANNEL;
goto SSH_NEW_CHANNEL;
case SSH_AUTH_PARTIAL:
case SSH_AUTH_DENIED:
client->state = SSH_AUTH_CLIENT_PUBKEY;
}
// fall through
case SSH_AUTH_CLIENT_PUBKEY:
case SSH_AUTH_CLIENT:
client->tried_passphrase = client->tmate_session->passphrase;
switch (ssh_userauth_publickey_auto(session, NULL, client->tried_passphrase)) {
switch (ssh_userauth_autopubkey(session, client->tried_passphrase)) {
case SSH_AUTH_AGAIN:
return;
case SSH_AUTH_PARTIAL:
@ -417,7 +319,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
request_passphrase(client);
} else {
kill_ssh_client(client, "SSH keys not found."
" Run 'ssh-keygen' to create keys.");
" Run 'ssh-keygen' to create keys and try again.");
return;
}
@ -429,20 +331,10 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
kill_ssh_client(client, "Auth error: %s", ssh_get_error(session));
return;
case SSH_AUTH_SUCCESS:
tmate_debug("Auth successful with pubkey");
client->state = SSH_NEW_CHANNEL;
tmate_debug("Auth successful");
client->state = SSH_OPEN_CHANNEL;
/* fall through */
}
// fall through
SSH_NEW_CHANNEL:
case SSH_NEW_CHANNEL:
client->channel = channel = ssh_channel_new(session);
if (!channel) {
tmate_fatal("cannot ssh_channel_new()");
return;
}
client->state = SSH_OPEN_CHANNEL;
// fall through
case SSH_OPEN_CHANNEL:
switch (ssh_channel_open_session(channel)) {
@ -453,10 +345,10 @@ SSH_NEW_CHANNEL:
ssh_get_error(session));
return;
case SSH_OK:
tmate_debug("Session opened, initializing tmate");
tmate_debug("Session opened, initalizing tmate");
client->state = SSH_BOOTSTRAP;
/* fall through */
}
// fall through
case SSH_BOOTSTRAP:
switch (ssh_channel_request_subsystem(channel, "tmate")) {
@ -484,8 +376,9 @@ SSH_NEW_CHANNEL:
free(client->tmate_session->last_server_ip);
client->tmate_session->last_server_ip = xstrdup(client->server_ip);
/* fall through */
}
// fall through
case SSH_READY:
read_channel(client);
@ -516,10 +409,9 @@ static void kill_ssh_client(struct tmate_ssh_client *client,
tmate_debug("SSH client killed (%s)", client->server_ip);
if (client->ev_ssh) {
event_del(client->ev_ssh);
event_free(client->ev_ssh);
client->ev_ssh = NULL;
if (client->has_init_conn_fd) {
event_del(&client->ev_ssh);
client->has_init_conn_fd = false;
}
if (client->state == SSH_READY) {
@ -545,11 +437,12 @@ static void kill_ssh_client(struct tmate_ssh_client *client,
free(client);
}
void connect_ssh_client(struct tmate_ssh_client *client)
static void connect_ssh_client(struct tmate_ssh_client *client)
{
assert(!client->session);
client->state = SSH_INIT;
on_ssh_client_event(client);
if (!client->session) {
client->state = SSH_INIT;
on_ssh_client_event(client);
}
}
static void ssh_log_function(int priority, const char *function,
@ -560,11 +453,9 @@ static void ssh_log_function(int priority, const char *function,
struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
const char *server_ip)
{
struct tmate_ssh_client *client;
client = xmalloc(sizeof(*client));
memset(client, 0, sizeof(*client));
ssh_set_log_callback(ssh_log_function);
@ -580,6 +471,11 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
client->state = SSH_NONE;
client->session = NULL;
client->channel = NULL;
client->has_encoder = 0;
client->has_init_conn_fd = false;
connect_ssh_client(client);
return client;
}

25
tmate.h
View file

@ -9,9 +9,10 @@
#include "tmux.h"
#define tmate_debug(...) log_emit(LOG_DEBUG, __VA_ARGS__)
#define tmate_info(...) log_emit(LOG_INFO, __VA_ARGS__)
#define tmate_fatal(...) fatalx( __VA_ARGS__)
#define tmate_debug(...) log_debug("[tmate] D " __VA_ARGS__)
#define tmate_warn(...) log_debug("[tmate] W " __VA_ARGS__)
#define tmate_info(...) log_debug("[tmate] I " __VA_ARGS__)
#define tmate_fatal(...) fatalx("[tmate] " __VA_ARGS__)
/* tmate-msgpack.c */
@ -22,7 +23,7 @@ struct tmate_encoder {
tmate_encoder_write_cb *ready_callback;
void *userdata;
struct evbuffer *buffer;
struct event *ev_buffer;
struct event ev_buffer;
bool ev_active;
};
@ -79,12 +80,10 @@ extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *neste
struct tmate_session;
extern void tmate_write_header(void);
extern void tmate_write_uname(void);
extern void tmate_write_ready(void);
extern void tmate_sync_layout(void);
extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len);
extern int tmate_should_replicate_cmd(const struct cmd_entry *cmd);
extern void tmate_set_val(const char *name, const char *value);
extern void tmate_exec_cmd_args(int argc, const char **argv);
extern void tmate_exec_cmd(struct cmd *cmd);
extern void tmate_failed_cmd(int client_id, const char *cause);
@ -107,9 +106,7 @@ enum tmate_ssh_client_state_types {
SSH_INIT,
SSH_CONNECT,
SSH_AUTH_SERVER,
SSH_AUTH_CLIENT_NONE,
SSH_AUTH_CLIENT_PUBKEY,
SSH_NEW_CHANNEL,
SSH_AUTH_CLIENT,
SSH_OPEN_CHANNEL,
SSH_BOOTSTRAP,
SSH_READY,
@ -130,6 +127,7 @@ struct tmate_ssh_client {
char *server_ip;
int has_encoder;
int state;
/*
@ -141,11 +139,11 @@ struct tmate_ssh_client {
ssh_session session;
ssh_channel channel;
struct event *ev_ssh;
bool has_init_conn_fd;
struct event ev_ssh;
};
TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client);
extern void connect_ssh_client(struct tmate_ssh_client *client);
extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
const char *server_ip);
@ -154,7 +152,7 @@ extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *ses
struct tmate_session {
struct event_base *ev_base;
struct evdns_base *ev_dnsbase;
struct event *ev_dns_retry;
struct event ev_dns_retry;
struct tmate_encoder encoder;
struct tmate_decoder decoder;
@ -175,7 +173,7 @@ struct tmate_session {
char *passphrase;
bool reconnected;
struct event *ev_connection_retry;
struct event ev_connection_retry;
char *last_server_ip;
char *reconnection_data;
/*
@ -202,7 +200,6 @@ extern void tmate_reconnect_session(struct tmate_session *session, const char *m
/* tmate-debug.c */
extern void tmate_print_stack_trace(void);
extern void tmate_catch_sigsegv(void);
extern void tmate_preload_trace_lib(void);
/* tmate-msg.c */

75
tmux.1
View file

@ -15,15 +15,14 @@
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: March 25 2013 $
.Dt TMATE 1
.Dt TMUX 1
.Os
.Sh NAME
.Nm tmate
.Nd terminal multiplexer with instant terminal sharing
.Nm tmux
.Nd terminal multiplexer
.Sh SYNOPSIS
.Nm tmate
.Nm tmux
.Bk -words
.Op show-messages
.Op Fl 2CluvV
.Op Fl c Ar shell-command
.Op Fl f Ar file
@ -33,24 +32,13 @@
.Ek
.Sh DESCRIPTION
.Nm
is a terminal multiplexer with instant terminal sharing:
is a terminal multiplexer:
it enables a number of terminals to be created, accessed, and
controlled from a single screen and be shared with another mates.
controlled from a single screen.
.Nm
may be detached from a screen
and continue running in the background,
then later reattached, like as a daemon.
.Pp
.Nm
provides an instant pairing solution, allowing you to share a terminal
with one or several teammates. Together with a voice call, it's almost like
pairing in person. The terminal sharing works by using SSH connections to
backend servers maintained by tmate upstream developers; teammates need to be
given a randomly-generated token to be able to join a session.
.Pp
.Nm
is a modified version of tmux, and uses the same configurations such as
keybindings, color schemes, etc.
then later reattached.
.Pp
When
.Nm
@ -59,9 +47,9 @@ is started it creates a new
with a single
.Em window
and displays it on screen.
A status line at the bottom of the screen shows information
on the current session, such as ssh command to share with
your mate, and is used to enter interactive commands.
A status line at the bottom of the screen
shows information on the current session
and is used to enter interactive commands.
.Pp
A session is a single collection of
.Em pseudo terminals
@ -92,7 +80,7 @@ key strokes).
.Nm
may be reattached using:
.Pp
.Dl $ tmate attach
.Dl $ tmux attach
.Pp
In
.Nm ,
@ -110,10 +98,6 @@ The options are as follows:
Force
.Nm
to assume the terminal supports 256 colours.
.It Fl a Ar file
Limit access to the public keys listed in the
.Ar file
given as argument.
.It Fl C
Start in control mode (see the
.Sx CONTROL MODE
@ -142,9 +126,7 @@ By default,
loads the system configuration file from
.Pa @SYSCONFDIR@/tmux.conf ,
if present, then looks for a user configuration file at
.Pa ~/.tmux.conf
and
.Pa ~/.tmate.conf .
.Pa ~/.tmux.conf .
.Pp
The configuration file is a set of
.Nm
@ -185,9 +167,7 @@ directories are missing).
.It Fl l
Behave as a login shell.
This flag currently has no effect and is for compatibility with other shells
when using
.Nm
as a login shell.
when using tmux as a login shell.
.It Fl S Ar socket-path
Specify a full alternative path to the server socket.
If
@ -617,7 +597,7 @@ to be given as multiple arguments and executed directly (without
This can avoid issues with shell quoting.
For example:
.Bd -literal -offset indent
$ tmate new-window vi /etc/passwd
$ tmux new-window vi /etc/passwd
.Ed
.Pp
Will run
@ -636,7 +616,7 @@ bind-key F1 set-window-option force-width 81
Or if using
.Xr sh 1 :
.Bd -literal -offset indent
$ tmate bind-key F1 set-window-option force-width 81
$ tmux bind-key F1 set-window-option force-width 81
.Ed
.Pp
Multiple commands may be specified together as part of a
@ -668,11 +648,11 @@ bind-key R source-file ~/.tmux.conf \e; \e
Or from
.Xr sh 1 :
.Bd -literal -offset indent
$ tmate kill-window -t :1
$ tmux kill-window -t :1
$ tmate new-window \e; split-window -d
$ tmux new-window \e; split-window -d
$ tmate new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach
$ tmux new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach
.Ed
.Sh CLIENTS AND SESSIONS
The
@ -1256,10 +1236,10 @@ command displays the layout of each window in a form suitable for use with
.Ic select-layout .
For example:
.Bd -literal -offset indent
$ tmate list-windows
$ tmux list-windows
0: ksh [159x48]
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
$ tmate select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
.Ed
.Pp
.Nm
@ -2327,8 +2307,8 @@ User options may have any name, so long as they are prefixed with
and be set to any string.
For example:
.Bd -literal -offset indent
$ tmate setw -q @foo "abc123"
$ tmate showw -v @foo
$ tmux setw -q @foo "abc123"
$ tmux showw -v @foo
abc123
.Ed
.Pp
@ -2414,8 +2394,7 @@ to work correctly, this
.Em must
be set to
.Ql screen ,
.Ql tmux ,
.Ql tmate
.Ql tmux
or a derivative of them.
.It Ic escape-time Ar time
Set the time in milliseconds for which
@ -4193,18 +4172,18 @@ To create a new
session running
.Xr vi 1 :
.Pp
.Dl $ tmate new-session vi
.Dl $ tmux new-session vi
.Pp
Most commands have a shorter form, known as an alias.
For new-session, this is
.Ic new :
.Pp
.Dl $ tmate new vi
.Dl $ tmux new vi
.Pp
Alternatively, the shortest unambiguous form of a command is accepted.
If there are several options, they are listed:
.Bd -literal -offset indent
$ tmate n
$ tmux n
ambiguous command: n, could be: new-session, new-window, next-window
.Ed
.Pp
@ -4234,7 +4213,7 @@ A session may be detached using
.Xr ssh 1
disconnection) and reattached with:
.Pp
.Dl $ tmate attach-session
.Dl $ tmux attach-session
.Pp
Typing
.Ql C-b \&?

71
tmux.c
View file

@ -48,30 +48,16 @@ __dead void usage(void);
static char *make_label(const char *);
#ifndef HAVE___PROGNAME
char *__progname = (char *) "tmate";
#endif
#ifdef TMATE
int tmate_foreground;
char *__progname = (char *) "tmux";
#endif
__dead void
usage(void)
{
fprintf(stderr,
"Usage: %s [options] [tmux-command [flags]]\n"
"\n"
"Basic options:\n"
" -n <name> specify the session token instead of getting a random one\n"
" -r <name> same, but for the read-only token\n"
" -k <key> specify an api-key, necessary for using named sessions on tmate.io\n"
" -F set the foreground mode, useful for setting remote access\n"
" -f <path> set the config file path\n"
" -S <path> set the socket path, useful to issue commands to a running tmate instance\n"
" -a <path> limit access to ssh public keys listed in provided file\n"
" -v set verbosity (can be repeated)\n"
" -V print version\n"
,__progname);
"usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n"
" [-S socket-path] [command [flags]]\n",
__progname);
exit(1);
}
@ -212,29 +198,6 @@ find_home(void)
return (home);
}
#ifdef TMATE
static char *api_key;
static char *session_name;
static char *session_name_ro;
static char *authorized_keys;
void tmate_load_cli_options(void)
{
#define SET_OPT(name, val) ({\
if (val) { \
run_headless_command(3, (const char *[]){"set-option", name, val}, DEFER_ERRORS_CFG, NULL); \
free(val); \
val = NULL; \
} \
})
SET_OPT("tmate-api-key", api_key);
SET_OPT("tmate-session-name", session_name);
SET_OPT("tmate-session-name-ro", session_name_ro);
SET_OPT("tmate-authorized-keys", authorized_keys);
#undef SET_OPT
}
#endif
int
main(int argc, char **argv)
{
@ -242,12 +205,12 @@ main(int argc, char **argv)
const char *s;
int opt, flags, keys;
if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL &&
setlocale(LC_CTYPE, "C.UTF-8") == NULL) {
if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) {
if (setlocale(LC_CTYPE, "") == NULL)
errx(1, "invalid LC_ALL, LC_CTYPE or LANG");
s = nl_langinfo(CODESET);
if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0)
if (strcasecmp(s, "UTF-8") != 0 &&
strcasecmp(s, "UTF8") != 0)
errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s);
}
@ -265,7 +228,7 @@ main(int argc, char **argv)
#endif
label = path = NULL;
while ((opt = getopt(argc, argv, "h2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) {
while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) {
switch (opt) {
case '2':
flags |= CLIENT_256COLOURS;
@ -305,24 +268,6 @@ main(int argc, char **argv)
case 'v':
log_add_level();
break;
case 'F':
tmate_foreground = 1;
log_add_level();
unsetenv("TMUX");
break;
case 'k':
api_key = xstrdup(optarg);
break;
case 'n':
session_name = xstrdup(optarg);
break;
case 'r':
session_name_ro = xstrdup(optarg);
break;
case 'a':
authorized_keys = xstrdup(optarg);
break;
case 'h':
default:
usage();
}

19
tmux.h
View file

@ -53,9 +53,7 @@ struct tmuxpeer;
struct tmuxproc;
/* Default global configuration file. */
#ifndef TMUX_CONF
#define TMUX_CONF "/etc/tmux.conf"
#endif
/*
* Minimum layout cell size, NOT including separator line. The scroll region
@ -1551,10 +1549,6 @@ extern struct options *global_w_options;
extern struct environ *global_environ;
extern struct timeval start_time;
extern const char *socket_path;
#ifdef TMATE
extern int tmate_foreground;
void tmate_load_cli_options(void);
#endif
const char *getshell(void);
int checkshell(const char *);
int areshell(const char *);
@ -1578,8 +1572,6 @@ void proc_kill_peer(struct tmuxpeer *);
extern int cfg_finished;
extern int cfg_references;
extern struct client *cfg_client;
extern char **cfg_causes;
extern u_int cfg_ncauses;
void start_cfg(void);
int load_cfg(const char *, struct cmd_q *, char **);
void set_cfg_file(const char *);
@ -1883,9 +1875,6 @@ void signal_waiting_clients(const char *name);
void cmd_wait_for_flush(void);
/* client.c */
#define DEFER_ERRORS_CFG 1
int run_headless_command(int argc, const char **argv, int flags, void (*err_callback)(const char *));
void run_initial_client_cmd(void);
int client_main(struct event_base *, int, char **, int, const char *);
/* key-bindings.c */
@ -1913,7 +1902,6 @@ void alerts_queue(struct window *, int);
void alerts_check_session(struct session *);
/* server.c */
extern int server_exit;
extern struct tmuxproc *server_proc;
extern struct clients clients;
extern struct cmd_find_state marked_pane;
@ -2368,14 +2356,9 @@ struct event_base *osdep_event_init(void);
/* log.c */
void log_add_level(void);
int log_get_level(void);
void log_open_fp(FILE *f);
void log_open(const char *);
void log_close(void);
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#define log_debug(...) log_emit(LOG_DEBUG+1, __VA_ARGS__)
void printflike(2, 3) log_emit(int level, const char *, ...);
void printflike(1, 2) log_debug(const char *, ...);
__dead void printflike(1, 2) fatal(const char *, ...);
__dead void printflike(1, 2) fatalx(const char *, ...);

View file

@ -1054,11 +1054,6 @@ window_copy_search_up(struct window_pane *wp, const char *searchstr)
int n, wrapped, wrapflag, cis;
const char *ptr;
#ifdef TMATE
if (!searchstr)
return;
#endif
if (*searchstr == '\0')
return;
wrapflag = options_get_number(wp->window->options, "wrap-search");
@ -1125,11 +1120,6 @@ window_copy_search_down(struct window_pane *wp, const char *searchstr)
int n, wrapped, wrapflag, cis;
const char *ptr;
#ifdef TMATE
if (!searchstr)
return;
#endif
if (*searchstr == '\0')
return;
wrapflag = options_get_number(wp->window->options, "wrap-search");

View file

@ -94,7 +94,6 @@ xasprintf(char **ret, const char *fmt, ...)
return i;
}
__attribute__((__format__(__printf__, 2, 0)))
int
xvasprintf(char **ret, const char *fmt, va_list ap)
{
@ -121,7 +120,6 @@ xsnprintf(char *str, size_t len, const char *fmt, ...)
return i;
}
__attribute__((__format__(__printf__, 3, 0)))
int
xvsnprintf(char *str, size_t len, const char *fmt, va_list ap)
{