diff --git a/configure.ac b/configure.ac index 68f4522..804b6fc 100644 --- a/configure.ac +++ b/configure.ac @@ -176,13 +176,32 @@ AC_ARG_WITH([skalibs-libdir], [specify exact library dir for skalibs libraries])], [SKALIBS_LDFLAGS="-L$withval"]) -AM_CONDITIONAL([COND_THIRD_LIBSTDDJB], [test x"$with_skalibs" = xno]) +STDDJB_CPPFLAGS="" +STDDJB_LDFLAGS="" AS_IF([test x"$with_skalibs" != xno], [AX_CHECK_LIBRARY([SKALIBS], [selfpipe.h], [stddjb], [], [AC_MSG_ERROR([Unable to find skalibs.])]) AC_SUBST([STDDJB_CPPFLAGS], ["$SKALIBS_CPPFLAGS"]) AC_SUBST([STDDJB_LDFLAGS], ["$SKALIBS_LDFLAGS -lstddjb"])]) +have_signalfd="no" +AC_CHECK_DECL([signalfd], + [have_signalfd="yes" + AC_DEFINE([HAVE_SIGNALFD], [1], + [Define if signalfd is available.])], + , [[#include ]]) + +AS_IF([test x"$have_signalfd" = xno], + [AC_DEFINE([USE_LIBSTDDJB], [1], + [Define if we should call functions from libstddjb (part of skalibs)])]) +AM_CONDITIONAL([USE_LIBSTDDJB], + [test x"$have_signalfd" = xno]) + +# Build the bundled libstddjb only if we'll use it and we don't have a +# path for skalibs. +AM_CONDITIONAL([COND_THIRD_LIBSTDDJB], + [test x"$have_signalfd" = xno && test x"$with_skalibs" = xno]) + # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h langinfo.h limits.h locale.h netinet/in.h stddef.h stdint.h inttypes.h stdlib.h string.h sys/ioctl.h sys/resource.h sys/socket.h sys/time.h term.h termios.h unistd.h wchar.h wctype.h], [], [AC_MSG_ERROR([Missing required header file.])]) @@ -239,11 +258,6 @@ AC_CHECK_DECL([pipe2], , [[#define _GNU_SOURCE #include ]]) -AC_CHECK_DECL([signalfd], - [AC_DEFINE([HAVE_SIGNALFD], [1], - [Define if signalfd is available.])], - , [[#include ]]) - AC_CHECK_DECL([forkpty], [AC_DEFINE([FORKPTY_IN_LIBUTIL], [1], [Define if libutil.h necessary for forkpty().])], diff --git a/debian/control b/debian/control index b28911e..b7400b4 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: mosh Section: net Priority: optional Maintainer: Keith Winstein -Build-Depends: debhelper (>= 7.0.50), autotools-dev, protobuf-compiler, libprotobuf-dev, dh-autoreconf, pkg-config, libutempter-dev, libboost-dev, zlib1g-dev, skalibs-dev, libncurses5-dev +Build-Depends: debhelper (>= 7.0.50), autotools-dev, protobuf-compiler, libprotobuf-dev, dh-autoreconf, pkg-config, libutempter-dev, libboost-dev, zlib1g-dev, libncurses5-dev Standards-Version: 3.9.3 Homepage: http://mosh.mit.edu Vcs-Git: git://github.com/keithw/mosh.git diff --git a/debian/rules b/debian/rules index c4e5743..9a90c54 100755 --- a/debian/rules +++ b/debian/rules @@ -15,5 +15,4 @@ override_dh_auto_configure: dh_auto_configure -- \ --disable-silent-rules \ - --enable-compile-warnings=error \ - --with-skalibs=/usr/lib/skalibs + --enable-compile-warnings=error diff --git a/src/examples/benchmark.cc b/src/examples/benchmark.cc index 923c3c9..cecea4e 100644 --- a/src/examples/benchmark.cc +++ b/src/examples/benchmark.cc @@ -38,10 +38,7 @@ #include #endif -extern "C" { -#include "selfpipe.h" -} - +#include "sigfd.h" #include "swrite.h" #include "completeterminal.h" #include "user.h" diff --git a/src/examples/termemu.cc b/src/examples/termemu.cc index f43afb6..9f7fd51 100644 --- a/src/examples/termemu.cc +++ b/src/examples/termemu.cc @@ -50,10 +50,7 @@ #include "swrite.h" #include "fatal_assert.h" #include "locale_utils.h" - -extern "C" { -#include "selfpipe.h" -} +#include "sigfd.h" const size_t buf_size = 16384; @@ -197,13 +194,13 @@ bool tick( Terminal::Framebuffer &state, Terminal::Framebuffer &new_frame, void emulate_terminal( int fd ) { /* establish WINCH fd and start listening for signal */ - int signal_fd = selfpipe_init(); + int signal_fd = sigfd_init(); if ( signal_fd < 0 ) { - perror( "selfpipe" ); + perror( "sigfd_init" ); return; } - fatal_assert( selfpipe_trap(SIGWINCH) == 0 ); + fatal_assert( sigfd_trap(SIGWINCH) == 0 ); /* get current window size */ struct winsize window_size; @@ -291,7 +288,7 @@ void emulate_terminal( int fd ) } } else if ( pollfds[ 2 ].revents & POLLIN ) { /* resize */ - fatal_assert( selfpipe_read() == SIGWINCH ); + fatal_assert( sigfd_read() == SIGWINCH ); /* get new size */ if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) { diff --git a/src/frontend/mosh-server.cc b/src/frontend/mosh-server.cc index 9a00d42..0b2773d 100644 --- a/src/frontend/mosh-server.cc +++ b/src/frontend/mosh-server.cc @@ -40,10 +40,7 @@ #include #include -extern "C" { -#include "selfpipe.h" -} - +#include "sigfd.h" #include "completeterminal.h" #include "swrite.h" #include "user.h" @@ -367,14 +364,14 @@ int run_server( const char *desired_ip, const char *desired_port, void serve( int host_fd, Terminal::Complete &terminal, ServerConnection &network ) { /* establish fd for shutdown signals */ - int signal_fd = selfpipe_init(); + int signal_fd = sigfd_init(); if ( signal_fd < 0 ) { - perror( "selfpipe_init" ); + perror( "sigfd_init" ); return; } - fatal_assert( selfpipe_trap( SIGTERM ) == 0 ); - fatal_assert( selfpipe_trap( SIGINT ) == 0 ); + fatal_assert( sigfd_trap( SIGTERM ) == 0 ); + fatal_assert( sigfd_trap( SIGINT ) == 0 ); /* prepare to poll for events */ struct pollfd pollfds[ 3 ]; @@ -516,11 +513,11 @@ void serve( int host_fd, Terminal::Complete &terminal, ServerConnection &network if ( pollfds[ 2 ].revents & POLLIN ) { /* shutdown signal */ - int signo = selfpipe_read(); + int signo = sigfd_read(); if ( signo == 0 ) { break; } else if ( signo < 0 ) { - perror( "selfpipe_read" ); + perror( "sigfd_read" ); break; } diff --git a/src/frontend/stmclient.cc b/src/frontend/stmclient.cc index 5a57783..f9cfb67 100644 --- a/src/frontend/stmclient.cc +++ b/src/frontend/stmclient.cc @@ -37,10 +37,7 @@ #include #endif -extern "C" { -#include "selfpipe.h" -} - +#include "sigfd.h" #include "stmclient.h" #include "swrite.h" #include "completeterminal.h" @@ -105,19 +102,19 @@ void STMClient::shutdown( void ) void STMClient::main_init( void ) { /* establish a fd for signals */ - signal_fd = selfpipe_init(); + signal_fd = sigfd_init(); if ( signal_fd < 0 ) { - perror( "selfpipe_init" ); + perror( "sigfd_init" ); return; } - fatal_assert( selfpipe_trap( SIGWINCH ) == 0 ); - fatal_assert( selfpipe_trap( SIGTERM ) == 0 ); - fatal_assert( selfpipe_trap( SIGINT ) == 0 ); - fatal_assert( selfpipe_trap( SIGHUP ) == 0 ); - fatal_assert( selfpipe_trap( SIGPIPE ) == 0 ); - fatal_assert( selfpipe_trap( SIGTSTP ) == 0 ); - fatal_assert( selfpipe_trap( SIGCONT ) == 0 ); + fatal_assert( sigfd_trap( SIGWINCH ) == 0 ); + fatal_assert( sigfd_trap( SIGTERM ) == 0 ); + fatal_assert( sigfd_trap( SIGINT ) == 0 ); + fatal_assert( sigfd_trap( SIGHUP ) == 0 ); + fatal_assert( sigfd_trap( SIGPIPE ) == 0 ); + fatal_assert( sigfd_trap( SIGTSTP ) == 0 ); + fatal_assert( sigfd_trap( SIGCONT ) == 0 ); /* get initial window size */ if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) { @@ -325,7 +322,7 @@ void STMClient::main( void ) } if ( pollfds[ 2 ].revents & POLLIN ) { - int signo = selfpipe_read(); + int signo = sigfd_read(); if ( signo == SIGWINCH ) { /* resize */ diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 1ab3133..ad4ed8d 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -2,4 +2,8 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) $(HARDEN_CFLAGS) $(MISC_CXXF noinst_LIBRARIES = libmoshutil.a -libmoshutil_a_SOURCES = locale_utils.cc locale_utils.h swrite.cc swrite.h dos_assert.h fatal_assert.h +libmoshutil_a_SOURCES = locale_utils.cc locale_utils.h swrite.cc swrite.h dos_assert.h fatal_assert.h sigfd.h + +if !USE_LIBSTDDJB + libmoshutil_a_SOURCES += sigfd.cc +endif diff --git a/src/util/sigfd.cc b/src/util/sigfd.cc new file mode 100644 index 0000000..824f453 --- /dev/null +++ b/src/util/sigfd.cc @@ -0,0 +1,75 @@ +/* + Mosh: the mobile shell + Copyright 2012 Keith Winstein + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include + +#include "fatal_assert.h" + +static sigset_t caught; +static int fd = -1; + +#define SIGNALFD_FLAGS ( SFD_NONBLOCK | SFD_CLOEXEC ) + +int sigfd_init( void ) +{ + if ( fd != -1 ) { + errno = EBUSY; + return -1; + } + sigemptyset( &caught ); + fd = signalfd( -1, &caught, SIGNALFD_FLAGS ); + return fd; +} + +int sigfd_trap( int sig ) +{ + /* The callers all fatal_assert on error, so we can do the same here. + We still return 'int' in order to have the same API as libstddjb. */ + fatal_assert( 0 <= fd ); + fatal_assert( 0 <= sigaddset( &caught, sig ) ); + fatal_assert( 0 <= sigprocmask( SIG_BLOCK, &caught, NULL ) ); + fatal_assert( 0 <= signalfd( fd, &caught, SIGNALFD_FLAGS ) ); + return 0; +} + +int sigfd_read( void ) +{ + int r; + struct signalfd_siginfo si; + + do { + r = read( fd, &si, sizeof( si ) ); + } while ( ( r == -1 ) && ( errno == EINTR ) ); + + if ( r == -1 ) { + if ( errno == EAGAIN || errno == EWOULDBLOCK ) + /* No signal available */ + return 0; + return -1; + } else if ( r != sizeof( si ) ) { + /* Should never happen? + Includes r = 0, i.e. end of file */ + errno = EPIPE; + return -1; + } + + return (int) si.ssi_signo; +} diff --git a/src/util/sigfd.h b/src/util/sigfd.h new file mode 100644 index 0000000..d8d7905 --- /dev/null +++ b/src/util/sigfd.h @@ -0,0 +1,54 @@ +/* + Mosh: the mobile shell + Copyright 2012 Keith Winstein + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* Uses either signalfd or libstddjb's selfpipe to receive signals as part of + an event loop. + + selfpipe already does a fine job of interfacing to signalfd. But Debian and + Ubuntu want us to depend on the skalibs-dev package rather than build + libstddjb ourselves. That would be fine except that skalibs-dev has static + libraries only, and they aren't built with -fPIC. This interferes with + building mosh-{client,server} as position-independent executables, which + is a desirable security measure. + + So we have our own wrapper, which invokes either signalfd or selfpipe. And + we build it ourselves with our own flags, because it's part of the Mosh + project proper. */ + +#ifndef SIGFD_HPP +#define SIGFD_HPP + +#if USE_LIBSTDDJB + +extern "C" { +#include "selfpipe.h" +} + +#define sigfd_init selfpipe_init +#define sigfd_trap selfpipe_trap +#define sigfd_read selfpipe_read + +#else + +int sigfd_init( void ); +int sigfd_trap( int sig ); +int sigfd_read( void ); + +#endif + +#endif