changes to add command line arguments. also added automatic
restarting and daemonizing on unix. daemon sends log messages to syslog. unix now reads config file from file named on command line; if no command line arg then uses effective user's config file and if that's not there it finally tries /etc/synergy.conf. if there are no screens configured then one is added for the primary screen. broke some startup stuff on win32. also now timing out if X primary screen can't grab the mouse and keyboard. the server will just give up trying to switch screens. the grabs will fail is some other app has a grab and won't release it. note that kdm grabs the keyboard for the duration that the login window is displayed, effectively disabling synergy.
This commit is contained in:
parent
10f4e94557
commit
beda89fd53
|
@ -201,7 +201,7 @@ void CLog::output(int priority, char* msg)
|
|||
// print it
|
||||
CHoldLock lock(s_lock);
|
||||
if (s_outputter) {
|
||||
s_outputter(msg + g_maxPriorityLength - n);
|
||||
s_outputter(priority, msg + g_maxPriorityLength - n);
|
||||
}
|
||||
else {
|
||||
#if defined(CONFIG_PLATFORM_WIN32)
|
||||
|
|
13
base/CLog.h
13
base/CLog.h
|
@ -6,7 +6,18 @@
|
|||
|
||||
class CLog {
|
||||
public:
|
||||
typedef void (*Outputter)(const char*);
|
||||
enum {
|
||||
kFATAL,
|
||||
kERROR,
|
||||
kWARNING,
|
||||
kNOTE,
|
||||
kINFO,
|
||||
kDEBUG,
|
||||
kDEBUG1,
|
||||
kDEBUG2
|
||||
};
|
||||
|
||||
typedef void (*Outputter)(int priority, const char*);
|
||||
typedef void (*Lock)(bool lock);
|
||||
|
||||
//
|
||||
|
|
|
@ -30,7 +30,7 @@ private:
|
|||
public:
|
||||
CString m_neighbor[kLastDirection - kFirstDirection + 1];
|
||||
};
|
||||
typedef std::map<CString, CCell> CCellMap;
|
||||
typedef std::map<CString, CCell, CStringUtil::CaselessCmp> CCellMap;
|
||||
|
||||
public:
|
||||
typedef CCellMap::const_iterator internal_const_iterator;
|
||||
|
@ -65,8 +65,8 @@ public:
|
|||
|
||||
// manipulators
|
||||
|
||||
// note that case is preserved in screen names but has no effect
|
||||
// FIXME -- make that true
|
||||
// note that case is preserved in screen names but is ignored when
|
||||
// comparing names.
|
||||
|
||||
// add/remove screens
|
||||
void addScreen(const CString& name);
|
||||
|
|
|
@ -141,7 +141,7 @@ log((CLOG_INFO "failed to release hot key: %d", GetLastError()));
|
|||
nextMark();
|
||||
}
|
||||
|
||||
void CMSWindowsPrimaryScreen::leave()
|
||||
bool CMSWindowsPrimaryScreen::leave()
|
||||
{
|
||||
log((CLOG_INFO "leaving primary"));
|
||||
assert(m_active == false);
|
||||
|
@ -232,6 +232,8 @@ log((CLOG_INFO "failed to get hot key: %d", GetLastError()));
|
|||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMSWindowsPrimaryScreen::onConfigure()
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
virtual void open(CServer*);
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void leave();
|
||||
virtual bool leave();
|
||||
virtual void onConfigure();
|
||||
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||
|
|
|
@ -63,6 +63,7 @@ CServer::CServer() : m_cleanupSize(&m_mutex, 0),
|
|||
|
||||
CServer::~CServer()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void CServer::run()
|
||||
|
@ -108,7 +109,9 @@ void CServer::run()
|
|||
cleanupThreads();
|
||||
delete m_httpServer;
|
||||
m_httpServer = NULL;
|
||||
closePrimaryScreen();
|
||||
if (m_primary != NULL) {
|
||||
closePrimaryScreen();
|
||||
}
|
||||
}
|
||||
catch (XThread&) {
|
||||
// clean up
|
||||
|
@ -709,6 +712,10 @@ void CServer::switchScreen(CScreenInfo* dst,
|
|||
log((CLOG_NOTE "switch from \"%s\" to \"%s\" at %d,%d", m_active->m_name.c_str(), dst->m_name.c_str(), x, y));
|
||||
// FIXME -- we're not locked here but we probably should be
|
||||
|
||||
// record new position
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
|
||||
// wrapping means leaving the active screen and entering it again.
|
||||
// since that's a waste of time we skip that and just warp the
|
||||
// mouse.
|
||||
|
@ -716,18 +723,19 @@ void CServer::switchScreen(CScreenInfo* dst,
|
|||
// note if we're leaving the primary screen
|
||||
const bool leavingPrimary = (m_active->m_protocol == NULL);
|
||||
|
||||
// if leaving the primary screen then update the clipboards
|
||||
// that it owns
|
||||
// leave active screen
|
||||
if (leavingPrimary) {
|
||||
if (!m_primary->leave()) {
|
||||
// cannot leave primary screen
|
||||
log((CLOG_WARN "can't leave primary screen"));
|
||||
return;
|
||||
}
|
||||
|
||||
// update the clipboards that the primary screen owns
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
updatePrimaryClipboard(id);
|
||||
}
|
||||
}
|
||||
|
||||
// leave active screen
|
||||
if (leavingPrimary) {
|
||||
m_primary->leave();
|
||||
}
|
||||
else {
|
||||
m_active->m_protocol->sendLeave();
|
||||
}
|
||||
|
@ -760,10 +768,6 @@ void CServer::switchScreen(CScreenInfo* dst,
|
|||
m_active->m_protocol->sendMouseMove(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// record new position
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
CServer::CScreenInfo* CServer::getNeighbor(CScreenInfo* src,
|
||||
|
@ -1333,8 +1337,10 @@ void CServer::openPrimaryScreen()
|
|||
m_primary->open(this);
|
||||
}
|
||||
catch (...) {
|
||||
delete m_primary;
|
||||
removeConnection(CString("primary"/* FIXME */));
|
||||
if (m_primary != NULL) {
|
||||
removeConnection(CString("primary"/* FIXME */));
|
||||
delete m_primary;
|
||||
}
|
||||
m_primary = NULL;
|
||||
m_primaryInfo = NULL;
|
||||
m_active = NULL;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "CXWindowsClipboard.h"
|
||||
#include "CXWindowsUtil.h"
|
||||
#include "CServer.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include <assert.h>
|
||||
|
@ -253,7 +254,7 @@ void CXWindowsPrimaryScreen::enter(SInt32 x, SInt32 y)
|
|||
m_active = false;
|
||||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::leave()
|
||||
bool CXWindowsPrimaryScreen::leave()
|
||||
{
|
||||
log((CLOG_INFO "leaving primary"));
|
||||
assert(m_active == false);
|
||||
|
@ -266,31 +267,43 @@ void CXWindowsPrimaryScreen::leave()
|
|||
|
||||
// grab the mouse and keyboard. keep trying until we get them.
|
||||
// if we can't grab one after grabbing the other then ungrab
|
||||
// and wait before retrying.
|
||||
// and wait before retrying. give up after s_timeout seconds.
|
||||
static const double s_timeout = 1.0;
|
||||
int result;
|
||||
CStopwatch timer;
|
||||
do {
|
||||
// mouse first
|
||||
// keyboard first
|
||||
do {
|
||||
result = XGrabPointer(display, m_window, True, 0,
|
||||
GrabModeAsync, GrabModeAsync,
|
||||
m_window, None, CurrentTime);
|
||||
assert(result != GrabNotViewable);
|
||||
if (result != GrabSuccess) {
|
||||
log((CLOG_DEBUG2 "waiting to grab pointer"));
|
||||
CThread::sleep(0.1);
|
||||
}
|
||||
} while (result != GrabSuccess);
|
||||
log((CLOG_DEBUG2 "grabbed pointer"));
|
||||
|
||||
// now the keyboard
|
||||
result = XGrabKeyboard(display, m_window, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
assert(result != GrabNotViewable);
|
||||
if (result != GrabSuccess) {
|
||||
log((CLOG_DEBUG2 "waiting to grab keyboard"));
|
||||
CThread::sleep(0.05);
|
||||
if (timer.getTime() >= s_timeout) {
|
||||
log((CLOG_DEBUG2 "grab keyboard timed out"));
|
||||
XUnmapWindow(display, m_window);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (result != GrabSuccess);
|
||||
log((CLOG_DEBUG2 "grabbed keyboard"));
|
||||
|
||||
// now the mouse
|
||||
result = XGrabPointer(display, m_window, True, 0,
|
||||
GrabModeAsync, GrabModeAsync,
|
||||
m_window, None, CurrentTime);
|
||||
assert(result != GrabNotViewable);
|
||||
if (result != GrabSuccess) {
|
||||
// back off to avoid grab deadlock
|
||||
XUngrabPointer(display, CurrentTime);
|
||||
log((CLOG_DEBUG2 "ungrabbed pointer, waiting to grab keyboard"));
|
||||
CThread::sleep(0.1);
|
||||
XUngrabKeyboard(display, CurrentTime);
|
||||
log((CLOG_DEBUG2 "ungrabbed keyboard, waiting to grab pointer"));
|
||||
CThread::sleep(0.05);
|
||||
if (timer.getTime() >= s_timeout) {
|
||||
log((CLOG_DEBUG2 "grab pointer timed out"));
|
||||
XUnmapWindow(display, m_window);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (result != GrabSuccess);
|
||||
log((CLOG_DEBUG1 "grabbed pointer and keyboard"));
|
||||
|
@ -302,6 +315,8 @@ void CXWindowsPrimaryScreen::leave()
|
|||
|
||||
// local client now active
|
||||
m_active = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::onConfigure()
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
virtual void open(CServer*);
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void leave();
|
||||
virtual bool leave();
|
||||
virtual void onConfigure();
|
||||
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||
|
|
|
@ -5,14 +5,36 @@
|
|||
#include "CNetwork.h"
|
||||
#include "CThread.h"
|
||||
#include "XThread.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "stdfstream.h"
|
||||
#include <assert.h>
|
||||
|
||||
static const char* s_copyright = "Copyright (C) 2002 Chris Schoeneman";
|
||||
static const SInt32 s_majorVersion = 0;
|
||||
static const SInt32 s_minorVersion = 5;
|
||||
static const char s_releaseVersion = ' ';
|
||||
|
||||
// configuration file name
|
||||
#if defined(CONFIG_PLATFORM_WIN32)
|
||||
#define CONFIG_NAME "synergy.sgc"
|
||||
#define CONFIG_USER_DIR "%HOME%/"
|
||||
#define CONFIG_SYS_DIR ""
|
||||
#elif defined(CONFIG_PLATFORM_UNIX)
|
||||
#define CONFIG_NAME "synergy.conf"
|
||||
#define CONFIG_USER_DIR "~/"
|
||||
#define CONFIG_SYS_DIR "/etc/"
|
||||
#endif
|
||||
|
||||
//
|
||||
// config file stuff
|
||||
// program arguments
|
||||
//
|
||||
|
||||
static const char* s_configFileName = "synergy.conf";
|
||||
static const char* pname = NULL;
|
||||
static bool s_restartable = true;
|
||||
static bool s_daemon = true;
|
||||
static const char* s_configFile = NULL;
|
||||
static const char* s_logFilter = NULL;
|
||||
static CConfig s_config;
|
||||
|
||||
|
||||
//
|
||||
|
@ -53,21 +75,15 @@ void realMain()
|
|||
// initialize network library
|
||||
CNetwork::init();
|
||||
|
||||
// load configuration
|
||||
CConfig config;
|
||||
{
|
||||
log((CLOG_DEBUG "opening configuration"));
|
||||
std::ifstream configStream(s_configFileName);
|
||||
if (!configStream) {
|
||||
throw XConfigRead("cannot open configuration");
|
||||
}
|
||||
configStream >> config;
|
||||
log((CLOG_DEBUG "configuration read successfully"));
|
||||
// if configuration has no screens then add this system
|
||||
// as the default
|
||||
if (s_config.begin() == s_config.end()) {
|
||||
s_config.addScreen("primary");
|
||||
}
|
||||
|
||||
// run server
|
||||
server = new CServer();
|
||||
server->setConfig(config);
|
||||
server->setConfig(s_config);
|
||||
server->run();
|
||||
|
||||
// clean up
|
||||
|
@ -86,6 +102,202 @@ void realMain()
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// command line parsing
|
||||
//
|
||||
|
||||
static void bye()
|
||||
{
|
||||
log((CLOG_PRINT "Try `%s --help' for more information.", pname));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void version()
|
||||
{
|
||||
log((CLOG_PRINT
|
||||
"%s %d.%d%c protocol version %d.%d\n"
|
||||
"%s",
|
||||
pname,
|
||||
s_majorVersion,
|
||||
s_minorVersion,
|
||||
s_releaseVersion,
|
||||
kMajorVersion,
|
||||
kMinorVersion,
|
||||
s_copyright));
|
||||
}
|
||||
|
||||
static void help()
|
||||
{
|
||||
log((CLOG_PRINT
|
||||
"Usage: %s"
|
||||
" [--config <pathname>]"
|
||||
" [--debug <level>]"
|
||||
" [--daemon|--no-daemon]"
|
||||
" [--restart|--no-restart]\n"
|
||||
"Start the synergy mouse/keyboard sharing server.\n"
|
||||
"\n"
|
||||
" -c, --config <pathname> use the named configuration file instead\n"
|
||||
" where ~ represents the user's home directory.\n"
|
||||
" -d, --debug <level> filter out log messages with priorty below level.\n"
|
||||
" level may be: FATAL, ERROR, WARNING, NOTE, INFO,\n"
|
||||
" DEBUG, DEBUG1, DEBUG2.\n"
|
||||
" -f, --no-daemon run the server in the foreground.\n"
|
||||
" --daemon run the server as a daemon.\n"
|
||||
" -1, --no-restart do not try to restart the server if it fails for\n"
|
||||
" some reason.\n"
|
||||
" --restart restart the server automatically if it fails.\n"
|
||||
" -h, --help display this help and exit.\n"
|
||||
" --version display version information and exit.\n"
|
||||
"\n"
|
||||
"By default, the server is a restartable daemon. If no configuration file\n"
|
||||
"pathname is provided then the first of the following to load sets the\n"
|
||||
"configuration:\n"
|
||||
" " CONFIG_USER_DIR CONFIG_NAME "\n"
|
||||
" " CONFIG_SYS_DIR CONFIG_NAME "\n"
|
||||
"If no configuration file can be loaded then the configuration uses its\n"
|
||||
"defaults with just the server screen.\n"
|
||||
"\n"
|
||||
"Where log messages go depends on the platform and whether or not the\n"
|
||||
"server is running as a daemon.",
|
||||
pname));
|
||||
|
||||
}
|
||||
|
||||
static bool loadConfig(const char* pathname, bool require)
|
||||
{
|
||||
assert(pathname != NULL);
|
||||
|
||||
try {
|
||||
// load configuration
|
||||
log((CLOG_DEBUG "opening configuration \"%s\"", pathname));
|
||||
std::ifstream configStream(pathname);
|
||||
if (!configStream) {
|
||||
throw XConfigRead("cannot open configuration");
|
||||
}
|
||||
configStream >> s_config;
|
||||
log((CLOG_DEBUG "configuration read successfully"));
|
||||
return true;
|
||||
}
|
||||
catch (XConfigRead& e) {
|
||||
if (require) {
|
||||
log((CLOG_PRINT "%s: cannot read configuration '%s'",
|
||||
pname, pathname));
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
log((CLOG_DEBUG "cannot read configuration \"%s\"", pathname));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isArg(int argi,
|
||||
int argc, char** argv,
|
||||
const char* name1,
|
||||
const char* name2,
|
||||
int minRequiredParameters = 0)
|
||||
{
|
||||
if ((name1 != NULL && strcmp(argv[argi], name1) == 0) ||
|
||||
(name2 != NULL && strcmp(argv[argi], name2) == 0)) {
|
||||
// match. check args left.
|
||||
if (argi + minRequiredParameters >= argc) {
|
||||
log((CLOG_PRINT "%s: missing arguments for `%s'",
|
||||
pname, argv[argi]));
|
||||
bye();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// no match
|
||||
return false;
|
||||
}
|
||||
|
||||
static void parse(int argc, char** argv)
|
||||
{
|
||||
assert(pname != NULL);
|
||||
assert(argv != NULL);
|
||||
assert(argc >= 1);
|
||||
|
||||
// parse options
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||
// change logging level
|
||||
s_logFilter = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
||||
// save configuration file path
|
||||
s_configFile = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||
// not a daemon
|
||||
s_daemon = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||
// daemonize
|
||||
s_daemon = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||
// don't try to restart
|
||||
s_restartable = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||
// try to restart
|
||||
s_restartable = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--version")) {
|
||||
version();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "--", NULL)) {
|
||||
// remaining arguments are not options
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (argv[i][0] == '-') {
|
||||
log((CLOG_PRINT "%s: unrecognized option `%s'", pname, argv[i]));
|
||||
bye();
|
||||
}
|
||||
|
||||
else {
|
||||
// this and remaining arguments are not options
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no non-option arguments are allowed
|
||||
if (i != argc) {
|
||||
log((CLOG_PRINT "%s: unrecognized option `%s'", pname, argv[i]));
|
||||
bye();
|
||||
}
|
||||
|
||||
// set log filter
|
||||
if (!CLog::setFilter(s_logFilter)) {
|
||||
log((CLOG_PRINT "%s: unrecognized log level `%s'", pname, s_logFilter));
|
||||
bye();
|
||||
}
|
||||
|
||||
// load the config file, if any
|
||||
if (s_configFile != NULL) {
|
||||
// require the user specified file to load correctly
|
||||
loadConfig(s_configFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// platform dependent entry points
|
||||
//
|
||||
|
@ -93,11 +305,39 @@ void realMain()
|
|||
#if defined(CONFIG_PLATFORM_WIN32)
|
||||
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include <string.h>
|
||||
|
||||
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
CMSWindowsScreen::init(instance);
|
||||
|
||||
// get program name
|
||||
pname = strrchr(argv[0], '/');
|
||||
if (pname == NULL) {
|
||||
pname = argv[0];
|
||||
}
|
||||
else {
|
||||
++pname;
|
||||
}
|
||||
const char* pname2 = strrchr(argv[0], '\\');
|
||||
if (pname2 != NULL && pname2 > pname) {
|
||||
pname = pname2 + 1;
|
||||
}
|
||||
|
||||
// FIXME -- direct CLog to MessageBox
|
||||
|
||||
parse(__argc, __argv);
|
||||
|
||||
// FIXME -- undirect CLog from MessageBox
|
||||
// FIXME -- if daemon then use win32 event log (however that's done),
|
||||
// otherwise do what? want to use console window for debugging but
|
||||
// not otherwise.
|
||||
|
||||
// load the configuration file if we haven't already
|
||||
if (s_configFile == NULL) {
|
||||
}
|
||||
|
||||
// FIXME
|
||||
if (__argc != 1) {
|
||||
CString msg = "no arguments allowed. exiting.";
|
||||
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
|
||||
|
@ -121,30 +361,189 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#elif defined(CONFIG_PLATFORM_UNIX)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static const char* s_configFileDefault = CONFIG_SYS_DIR CONFIG_NAME;
|
||||
|
||||
static void daemonize()
|
||||
{
|
||||
// fork so shell thinks we're done and so we're not a process
|
||||
// group leader
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
// failed
|
||||
log((CLOG_PRINT "failed to daemonize"));
|
||||
exit(1);
|
||||
|
||||
case 0:
|
||||
// child
|
||||
break;
|
||||
|
||||
default:
|
||||
// parent exits
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// become leader of a new session
|
||||
setsid();
|
||||
|
||||
// chdir to root so we don't keep mounted filesystems points busy
|
||||
chdir("/");
|
||||
|
||||
// mask off permissions for any but owner
|
||||
umask(077);
|
||||
|
||||
// close open files. we only expect stdin, stdout, stderr to be open.
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
// attach file descriptors 0, 1, 2 to /dev/null so inadvertent use
|
||||
// of standard I/O safely goes in the bit bucket.
|
||||
open("/dev/null", O_RDWR);
|
||||
dup(0);
|
||||
dup(0);
|
||||
}
|
||||
|
||||
static void syslogOutputter(int priority, const char* msg)
|
||||
{
|
||||
// convert priority
|
||||
switch (priority) {
|
||||
case CLog::kFATAL:
|
||||
case CLog::kERROR:
|
||||
priority = LOG_ERR;
|
||||
break;
|
||||
|
||||
case CLog::kWARNING:
|
||||
priority = LOG_WARNING;
|
||||
break;
|
||||
|
||||
case CLog::kNOTE:
|
||||
priority = LOG_NOTICE;
|
||||
break;
|
||||
|
||||
case CLog::kINFO:
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
|
||||
default:
|
||||
priority = LOG_DEBUG;
|
||||
break;
|
||||
}
|
||||
|
||||
// log it
|
||||
syslog(priority, "%s", msg);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "usage: %s\n", argv[0]);
|
||||
return 1;
|
||||
// get program name
|
||||
pname = strrchr(argv[0], '/');
|
||||
if (pname == NULL) {
|
||||
pname = argv[0];
|
||||
}
|
||||
else {
|
||||
++pname;
|
||||
}
|
||||
|
||||
try {
|
||||
realMain();
|
||||
return 0;
|
||||
// parse command line
|
||||
parse(argc, argv);
|
||||
|
||||
// load the configuration file if we haven't already
|
||||
if (s_configFile == NULL) {
|
||||
// get the user's home directory. use the effective user id
|
||||
// so a user can't get a setuid root program to load his file.
|
||||
bool loaded = false;
|
||||
struct passwd* pwent = getpwuid(geteuid());
|
||||
if (pwent != NULL && pwent->pw_dir != NULL) {
|
||||
// construct path if it isn't too long
|
||||
if (strlen(pwent->pw_dir) + strlen(CONFIG_NAME) + 2 <= PATH_MAX) {
|
||||
char path[PATH_MAX];
|
||||
strcpy(path, pwent->pw_dir);
|
||||
strcat(path, "/");
|
||||
strcat(path, CONFIG_NAME);
|
||||
|
||||
// now try loading the user's configuration
|
||||
loaded = loadConfig(path, false);
|
||||
}
|
||||
}
|
||||
if (!loaded) {
|
||||
// try the system-wide config file
|
||||
loadConfig(s_configFileDefault, false);
|
||||
}
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_CRIT "failed: %s", e.what()));
|
||||
fprintf(stderr, "failed: %s\n", e.what());
|
||||
return 1;
|
||||
|
||||
// daemonize if requested
|
||||
if (s_daemon) {
|
||||
daemonize();
|
||||
|
||||
// send log to syslog
|
||||
openlog("synergy", 0, LOG_DAEMON);
|
||||
CLog::setOutputter(&syslogOutputter);
|
||||
}
|
||||
catch (XThread&) {
|
||||
// terminated
|
||||
return 1;
|
||||
|
||||
// run the server. if running as a daemon then run it in a child
|
||||
// process and restart it as necessary. we have to do this in case
|
||||
// the X server restarts because our process cannot recover from
|
||||
// that.
|
||||
for (;;) {
|
||||
// don't fork if not restartable
|
||||
switch (s_restartable ? fork() : 0) {
|
||||
default: {
|
||||
// parent process. wait for child to exit.
|
||||
int status;
|
||||
if (wait(&status) == -1) {
|
||||
// wait failed. this is unexpected so bail.
|
||||
log((CLOG_CRIT "wait() failed"));
|
||||
return 16;
|
||||
}
|
||||
|
||||
// what happened? if the child exited normally with a
|
||||
// status less than 16 then the child was deliberately
|
||||
// terminated so we also terminate. otherwise, we
|
||||
// loop.
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) < 16) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case -1:
|
||||
// fork() failed. log the error and proceed as a child
|
||||
log((CLOG_WARN "fork() failed; cannot automatically restart on error"));
|
||||
// fall through
|
||||
|
||||
case 0:
|
||||
// child process
|
||||
try {
|
||||
realMain();
|
||||
return 0;
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_CRIT "failed: %s", e.what()));
|
||||
fprintf(stderr, "failed: %s\n", e.what());
|
||||
return 16;
|
||||
}
|
||||
catch (XThread&) {
|
||||
// terminated
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error no main() for platform
|
||||
|
||||
#endif
|
||||
|
|
|
@ -357,7 +357,7 @@ int CXWindowsScreen::ioErrorHandler(Display*)
|
|||
s_screen->m_display = NULL;
|
||||
s_screen->onUnexpectedClose();
|
||||
log((CLOG_CRIT "quiting due to X display disconnection"));
|
||||
exit(1);
|
||||
exit(17);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ public:
|
|||
|
||||
// called when the user navigates off the primary screen. hide
|
||||
// the cursor and grab exclusive access to the input devices.
|
||||
virtual void leave() = 0;
|
||||
// return true iff successful.
|
||||
virtual bool leave() = 0;
|
||||
|
||||
// called when the configuration has changed. subclasses may need
|
||||
// to adjust things (like the jump zones) after the configuration
|
||||
|
|
Loading…
Reference in New Issue