1009 lines
23 KiB
C
1009 lines
23 KiB
C
/* $Xorg: utils.c,v 1.5 2001/02/09 02:05:32 xorgcvs Exp $ */
|
|
/* $XdotOrg: $ */
|
|
/***********************************************************
|
|
|
|
Copyright 1987, 1996, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
|
|
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the name of Digital not be
|
|
used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
SOFTWARE.
|
|
|
|
******************************************************************/
|
|
/* $XFree86: xc/programs/lbxproxy/di/utils.c,v 1.17 2003/09/13 21:33:10 dawes Exp $ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "lbx.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h> /* getenv(), {m,re}alloc() */
|
|
#ifdef X_POSIX_C_SOURCE
|
|
#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
|
|
#include <signal.h>
|
|
#undef _POSIX_C_SOURCE
|
|
#else
|
|
#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
|
|
#include <signal.h>
|
|
#else
|
|
#define _POSIX_SOURCE
|
|
#include <signal.h>
|
|
#undef _POSIX_SOURCE
|
|
#endif
|
|
#endif
|
|
#if !defined(SYSV) && !defined(Lynx) && !defined(QNX4)
|
|
#include <sys/resource.h>
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
|
|
static void VErrorF(const char*, va_list);
|
|
|
|
#ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */
|
|
# define SIGVAL RETSIGTYPE
|
|
#else /* Imake */
|
|
#ifdef SIGNALRETURNSINT
|
|
#define SIGVAL int
|
|
#else
|
|
#define SIGVAL void
|
|
#endif
|
|
#endif /* RETSIGTYPE */
|
|
|
|
#include "util.h"
|
|
#include "wire.h"
|
|
#include "atomcache.h"
|
|
#include "proxyopts.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
/*
|
|
* External declarations not in header files
|
|
*/
|
|
extern Bool PartialNetwork;
|
|
extern int lbxDebug;
|
|
|
|
extern char protocolMode;
|
|
extern Bool reconnectAfterCloseServer;
|
|
extern Bool resetAfterLastClient;
|
|
extern Bool terminateAfterLastClient;
|
|
extern int lbxTagCacheSize;
|
|
extern Bool lbxUseLbx;
|
|
extern Bool lbxUseTags;
|
|
extern Bool lbxDoSquishing;
|
|
extern Bool lbxCompressImages;
|
|
extern Bool lbxDoAtomShortCircuiting;
|
|
extern Bool lbxDoLbxGfx;
|
|
extern Bool compStats;
|
|
|
|
/*
|
|
* Static vars
|
|
*/
|
|
static Bool CoreDump;
|
|
static Bool Must_have_memory = FALSE;
|
|
|
|
/*
|
|
* Debug stuff
|
|
*/
|
|
#ifdef DEBUG
|
|
#ifndef SPECIAL_MALLOC
|
|
#define MEMBUG
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef MEMBUG
|
|
#define MEM_FAIL_SCALE 100000
|
|
long Memory_fail = 0;
|
|
#endif
|
|
|
|
/*
|
|
* Global vars that may get set when the command line opts are parsed.
|
|
*/
|
|
#ifdef RGB_DB
|
|
char *rgbPath = RGB_DB;
|
|
#else
|
|
char *rgbPath;
|
|
#endif
|
|
|
|
Bool lbxZeroPad = TRUE; /* zero out pad bytes in X requests */
|
|
|
|
char *atomsFile = DEF_ATOMS_FILE;
|
|
|
|
Bool lbxWinAttr = TRUE; /* group GetWindowAttributes/GetGeometry into 1 trip */
|
|
|
|
Bool lbxDoCmapGrabbing = TRUE; /* do colormap grabbing? */
|
|
|
|
int lbxMaxMotionEvents = NUM_MOTION_EVENTS; /* max # motion events */
|
|
|
|
int min_keep_prop_size = DEF_KEEP_PROP_SIZE;
|
|
|
|
/*
|
|
* zlevel = 1..9, 9 == max compression. 6 == good tradeoff between
|
|
* compression and speed. Try gzipping a large file at the default
|
|
* level (which is 6) and at max compression (9) and notice the
|
|
* difference in time it takes to compress the file and the difference
|
|
* in file size. level 9 compression takes ~50 more (time, cpu) but
|
|
* only yields a very small improvement in compression.
|
|
*/
|
|
int zlevel = 6;
|
|
|
|
|
|
/*
|
|
* The functions
|
|
*/
|
|
OsSigHandlerPtr
|
|
OsSignal(sig, handler)
|
|
int sig;
|
|
OsSigHandlerPtr handler;
|
|
{
|
|
#ifdef X_NOT_POSIX
|
|
return signal(sig, handler);
|
|
#else
|
|
struct sigaction act, oact;
|
|
|
|
sigemptyset(&act.sa_mask);
|
|
if (handler != SIG_IGN)
|
|
sigaddset(&act.sa_mask, sig);
|
|
act.sa_flags = 0;
|
|
act.sa_handler = handler;
|
|
sigaction(sig, &act, &oact);
|
|
return oact.sa_handler;
|
|
#endif
|
|
}
|
|
|
|
/* Force connections to close on SIGHUP from init */
|
|
|
|
/* ARGSUSED */
|
|
SIGVAL
|
|
AutoResetServer (sig)
|
|
int sig;
|
|
{
|
|
dispatchException |= DE_RESET;
|
|
isItTimeToYield = TRUE;
|
|
#ifdef GPROF
|
|
chdir ("/tmp");
|
|
_exit (0);
|
|
#endif
|
|
#ifdef SYSV
|
|
signal (SIGHUP, AutoResetServer);
|
|
#endif
|
|
}
|
|
|
|
/* Force connections to close and then exit on SIGTERM, SIGINT */
|
|
|
|
/* ARGSUSED */
|
|
SIGVAL
|
|
GiveUp(sig)
|
|
int sig;
|
|
{
|
|
dispatchException |= DE_TERMINATE;
|
|
isItTimeToYield = TRUE;
|
|
}
|
|
|
|
static void
|
|
AbortServer()
|
|
{
|
|
fflush(stderr);
|
|
if (CoreDump)
|
|
abort();
|
|
exit (1);
|
|
}
|
|
|
|
void
|
|
Error(str)
|
|
char *str;
|
|
{
|
|
perror(str);
|
|
}
|
|
|
|
void UseMsg()
|
|
{
|
|
ErrorF("use: lbxproxy [:<display>] [option]\n");
|
|
#ifdef MEMBUG
|
|
ErrorF("-alloc int chance alloc should fail\n");
|
|
#endif
|
|
ErrorF("-help prints message with these options\n");
|
|
ErrorF("-display specify address of LBX server\n");
|
|
ErrorF("-motion # allow # motion events in flight\n");
|
|
ErrorF("-[terminate|reset] terminate or reset after last client exits\n");
|
|
ErrorF(" (default is continue running)\n");
|
|
ErrorF("-I ignore all remaining arguments\n");
|
|
ErrorF("-reconnect reset if server connection is broken\n");
|
|
ErrorF(" (default is to exit if connection is broken)\n");
|
|
ErrorF("-nolbx disable LBX reencoding of X requests\n");
|
|
ErrorF("-nocomp disable stream compression\n");
|
|
ErrorF("-nodelta disable request deltas\n");
|
|
ErrorF("-notags disable tags\n");
|
|
ErrorF("-nogfx disable graphics enhancements\n");
|
|
ErrorF("-noimage disable image compression\n");
|
|
ErrorF("-nosquish disable event squishing\n");
|
|
ErrorF("-nointernsc disable InternAtom short circuiting\n");
|
|
ErrorF("-noatomsfile disable atom control file\n");
|
|
ErrorF("-atomsfile override AtomControl file\n");
|
|
ErrorF("-nowinattr disable GetWindowAttributes/GetGeometry\n");
|
|
ErrorF(" grouping into one round trip\n");
|
|
ErrorF("-nograbcmap disable colormap grabbing\n");
|
|
ErrorF("-norgbfile disables color name to RGB resolution\n");
|
|
ErrorF("-rgbfile <path> path specifies an alternate RGB database\n");
|
|
ErrorF(" for color name to RGB resolution\n");
|
|
ErrorF("-tagcachesize # set tag cache size\n");
|
|
ErrorF("-maxservers # maximum number of servers to use\n");
|
|
ErrorF(" default is 20, but this is overrided\n");
|
|
ErrorF(" the following environment variable:\n");
|
|
ErrorF(" LBXPROXY_MAXSERVERS=<max servers>\n");
|
|
ErrorF("-zlevel # zlib compression level (1-9)\n");
|
|
ErrorF(" default is 9\n");
|
|
ErrorF(" 1 = worst compression, fastest\n");
|
|
ErrorF(" 9 = best compression, slowest\n");
|
|
ErrorF("-compstats report stream compression statistics\n");
|
|
ErrorF("-nozeropad don't zero out pad bytes in X requests\n");
|
|
ErrorF("-cheaterrors cheat on X protocol errors for better performance\n");
|
|
ErrorF("-cheatevents cheat on events and errors for better performance\n");
|
|
}
|
|
|
|
void
|
|
ShowHelpAndExit (status)
|
|
int status;
|
|
{
|
|
UseMsg ();
|
|
exit (status);
|
|
}
|
|
|
|
static int
|
|
proxyProcessArgument (argc, argv, i)
|
|
int argc;
|
|
char **argv;
|
|
int i;
|
|
{
|
|
if (strcmp (argv[i], "-debug") == 0)
|
|
{
|
|
if (++i < argc)
|
|
lbxDebug = atoi(argv[i]);
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-cheaterrors") == 0)
|
|
{
|
|
protocolMode = PROTOCOL_MOST;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-cheatevents") == 0)
|
|
{
|
|
protocolMode = PROTOCOL_POOR;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nolbx") == 0)
|
|
{
|
|
lbxUseLbx = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nointernsc") == 0)
|
|
{
|
|
lbxDoAtomShortCircuiting = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nocomp") == 0)
|
|
{
|
|
LbxNoComp();
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nodelta") == 0)
|
|
{
|
|
LbxNoDelta();
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-notags") == 0)
|
|
{
|
|
lbxUseTags = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nogfx") == 0)
|
|
{
|
|
lbxDoLbxGfx = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-noimage") == 0)
|
|
{
|
|
lbxCompressImages = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nosquish") == 0)
|
|
{
|
|
lbxDoSquishing = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nograbcmap") == 0)
|
|
{
|
|
lbxDoCmapGrabbing = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-reconnect") == 0)
|
|
{
|
|
reconnectAfterCloseServer = TRUE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-norgbfile") == 0)
|
|
{
|
|
rgbPath = NULL;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-rgbfile") == 0)
|
|
{
|
|
if (++i < argc)
|
|
if (argv[i][0] == '-')
|
|
ShowHelpAndExit (1);
|
|
else
|
|
rgbPath = argv[i];
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-nowinattr") == 0)
|
|
{
|
|
lbxWinAttr = FALSE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-noatomsfile") == 0)
|
|
{
|
|
atomsFile = NULL;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-atomsfile") == 0)
|
|
{
|
|
if (++i < argc)
|
|
{
|
|
if (argv[i][0] == '-')
|
|
ShowHelpAndExit (1);
|
|
else
|
|
atomsFile = argv[i];
|
|
}
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-tagcachesize") == 0)
|
|
{
|
|
if (++i < argc)
|
|
lbxTagCacheSize = atoi(argv[i]);
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-maxservers") == 0)
|
|
{
|
|
if (++i < argc)
|
|
lbxMaxServers = atoi(argv[i]);
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-motion") == 0)
|
|
{
|
|
if (++i < argc)
|
|
lbxMaxMotionEvents = atoi(argv[i]);
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-zlevel") == 0)
|
|
{
|
|
if (++i < argc)
|
|
{
|
|
zlevel = atoi(argv[i]);
|
|
if (zlevel < 1 || zlevel > 9)
|
|
ShowHelpAndExit (1);
|
|
}
|
|
else
|
|
ShowHelpAndExit (1);
|
|
return 2;
|
|
}
|
|
if (strcmp (argv[i], "-compstats") == 0)
|
|
{
|
|
compStats = TRUE;
|
|
return 1;
|
|
}
|
|
if (strcmp (argv[i], "-nozeropad") == 0)
|
|
{
|
|
lbxZeroPad = FALSE;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This function parses the command line. Handles device-independent fields
|
|
* and allows ddx to handle additional fields. It is not allowed to modify
|
|
* argc or any of the strings pointed to by argv.
|
|
*/
|
|
void
|
|
ProcessCommandLine ( argc, argv )
|
|
int argc;
|
|
char *argv[];
|
|
|
|
{
|
|
int i, skip;
|
|
char *env;
|
|
|
|
/*
|
|
* Some options may also be defined by environment variables.
|
|
* However, if this is the case, the command line options will
|
|
* take precedence so check the environment first.
|
|
*/
|
|
if ((env = getenv ("LBXPROXY_MAXSERVERS")))
|
|
lbxMaxServers = atoi (env);
|
|
|
|
for ( i = 1; i < argc; i++ )
|
|
{
|
|
/* do proxy-specific stuff first */
|
|
if((skip = proxyProcessArgument(argc, argv, i)))
|
|
{
|
|
i += (skip - 1);
|
|
}
|
|
else if(argv[i][0] == ':')
|
|
{
|
|
/* initialize display */
|
|
display = argv[i];
|
|
display++;
|
|
}
|
|
#ifdef MEMBUG
|
|
else if ( strcmp( argv[i], "-alloc") == 0)
|
|
{
|
|
if(++i < argc)
|
|
Memory_fail = atoi(argv[i]);
|
|
else
|
|
ShowHelpAndExit (1);
|
|
}
|
|
#endif
|
|
else if ( strcmp( argv[i], "-display") == 0)
|
|
{
|
|
if(++i < argc)
|
|
display_name = argv[i];
|
|
else
|
|
ShowHelpAndExit (1);
|
|
}
|
|
else if ( strcmp( argv[i], "-core") == 0)
|
|
CoreDump = TRUE;
|
|
else if ( strcmp( argv[i], "-help") == 0)
|
|
ShowHelpAndExit (0);
|
|
else if ( strcmp( argv[i], "-pn") == 0)
|
|
PartialNetwork = TRUE;
|
|
else if ( strcmp( argv[i], "-reset") == 0)
|
|
{
|
|
if (terminateAfterLastClient)
|
|
ShowHelpAndExit (1);
|
|
|
|
resetAfterLastClient = TRUE;
|
|
}
|
|
else if ( strcmp( argv[i], "-terminate") == 0)
|
|
{
|
|
if (resetAfterLastClient)
|
|
ShowHelpAndExit (1);
|
|
|
|
terminateAfterLastClient = TRUE;
|
|
}
|
|
else if ( strcmp( argv[i], "-I") == 0)
|
|
{
|
|
/* ignore all remaining arguments */
|
|
break;
|
|
}
|
|
else if (strncmp (argv[i], "tty", 3) == 0)
|
|
{
|
|
/* Ignored */
|
|
}
|
|
else
|
|
ShowHelpAndExit (1);
|
|
}
|
|
}
|
|
|
|
/* XALLOC -- X's internal memory allocator. Why does it return unsigned
|
|
* int * instead of the more common char *? Well, if you read K&R you'll
|
|
* see they say that alloc must return a pointer "suitable for conversion"
|
|
* to whatever type you really want. In a full-blown generic allocator
|
|
* there's no way to solve the alignment problems without potentially
|
|
* wasting lots of space. But we have a more limited problem. We know
|
|
* we're only ever returning pointers to structures which will have to
|
|
* be long word aligned. So we are making a stronger guarantee. It might
|
|
* have made sense to make Xalloc return char * to conform with people's
|
|
* expectations of malloc, but this makes lint happier.
|
|
*/
|
|
|
|
unsigned long *
|
|
Xalloc (amount)
|
|
unsigned long amount;
|
|
{
|
|
register pointer ptr;
|
|
|
|
if ((long)amount <= 0)
|
|
return (unsigned long *)NULL;
|
|
/* aligned extra on long word boundary */
|
|
amount = (amount + 3) & ~3;
|
|
#ifdef MEMBUG
|
|
if (!Must_have_memory && Memory_fail &&
|
|
((random() % MEM_FAIL_SCALE) < Memory_fail))
|
|
return (unsigned long *)NULL;
|
|
#endif
|
|
if ((ptr = (pointer)malloc(amount)))
|
|
return (unsigned long *)ptr;
|
|
if (Must_have_memory)
|
|
FatalError("Out of memory");
|
|
return (unsigned long *)NULL;
|
|
}
|
|
|
|
/*****************
|
|
* Xcalloc
|
|
*****************/
|
|
|
|
unsigned long *
|
|
Xcalloc (amount)
|
|
unsigned long amount;
|
|
{
|
|
unsigned long *ret;
|
|
|
|
ret = Xalloc (amount);
|
|
if (ret)
|
|
bzero ((char *) ret, (int) amount);
|
|
return ret;
|
|
}
|
|
|
|
/*****************
|
|
* Xrealloc
|
|
*****************/
|
|
|
|
unsigned long *
|
|
Xrealloc (ptr, amount)
|
|
register pointer ptr;
|
|
unsigned long amount;
|
|
{
|
|
#ifdef MEMBUG
|
|
if (!Must_have_memory && Memory_fail &&
|
|
((random() % MEM_FAIL_SCALE) < Memory_fail))
|
|
return (unsigned long *)NULL;
|
|
#endif
|
|
if ((long)amount <= 0)
|
|
{
|
|
if (ptr && !amount)
|
|
free(ptr);
|
|
return (unsigned long *)NULL;
|
|
}
|
|
amount = (amount + 3) & ~3;
|
|
if (ptr)
|
|
ptr = (pointer)realloc((char *)ptr, amount);
|
|
else
|
|
ptr = (pointer)malloc(amount);
|
|
if (ptr)
|
|
return (unsigned long *)ptr;
|
|
if (Must_have_memory)
|
|
FatalError("Out of memory");
|
|
return (unsigned long *)NULL;
|
|
}
|
|
|
|
/*****************
|
|
* Xfree
|
|
* calls free
|
|
*****************/
|
|
|
|
void
|
|
Xfree(ptr)
|
|
register pointer ptr;
|
|
{
|
|
if (ptr)
|
|
free((char *)ptr);
|
|
}
|
|
|
|
void
|
|
OsInitAllocator ()
|
|
{
|
|
#ifdef MEMBUG
|
|
static int been_here;
|
|
|
|
/* Check the memory system after each generation */
|
|
if (been_here)
|
|
CheckMemory ();
|
|
else
|
|
been_here = 1;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
AuditF(const char * f, ...)
|
|
{
|
|
#ifdef notyet /* ever ? */
|
|
time_t tm;
|
|
char *autime, *s;
|
|
va_list args;
|
|
|
|
if (*f != ' ')
|
|
{
|
|
time(&tm);
|
|
autime = ctime(&tm);
|
|
if (s = strchr(autime, '\n'))
|
|
*s = '\0';
|
|
if (s = strrchr(argvGlobal[0], '/'))
|
|
s++;
|
|
else
|
|
s = argvGlobal[0];
|
|
ErrorF("AUDIT: %s: %d %s: ", autime, getpid(), s);
|
|
}
|
|
va_start(args, f);
|
|
VErrorF(f, args);
|
|
va_end(args);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
FatalError(const char *f, ...)
|
|
{
|
|
va_list args;
|
|
ErrorF("\nFatal lbxproxy error: ");
|
|
va_start(args, f);
|
|
VErrorF(f, args);
|
|
va_end(args);
|
|
ErrorF("\n");
|
|
AbortServer();
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
static void
|
|
VErrorF(const char *f, va_list args)
|
|
{
|
|
vfprintf(stderr, f, args);
|
|
}
|
|
|
|
void
|
|
ErrorF(const char * f, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, f);
|
|
VErrorF(f, args);
|
|
va_end(args);
|
|
}
|
|
|
|
char *
|
|
strnalloc(str, len)
|
|
char *str;
|
|
int len;
|
|
{
|
|
char *t;
|
|
|
|
t = (char *) Xalloc(len);
|
|
if (!t)
|
|
return (char *) 0;
|
|
memcpy(t, str, len);
|
|
return t;
|
|
}
|
|
|
|
/*
|
|
* A general work queue. Perform some task before the server
|
|
* sleeps for input.
|
|
*/
|
|
|
|
typedef struct _WorkQueue {
|
|
struct _WorkQueue *next;
|
|
Bool (*function) (
|
|
ClientPtr /* pClient */,
|
|
pointer /* closure */
|
|
);
|
|
ClientPtr client;
|
|
pointer closure;
|
|
} WorkQueueRec;
|
|
|
|
WorkQueuePtr workQueue;
|
|
static WorkQueuePtr *workQueueLast = &workQueue;
|
|
|
|
/* ARGSUSED */
|
|
void
|
|
ProcessWorkQueue()
|
|
{
|
|
WorkQueuePtr q, n, p;
|
|
|
|
p = NULL;
|
|
/*
|
|
* Scan the work queue once, calling each function. Those
|
|
* which return TRUE are removed from the queue, otherwise
|
|
* they will be called again. This must be reentrant with
|
|
* QueueWorkProc, hence the crufty usage of variables.
|
|
*/
|
|
for (q = workQueue; q; q = n)
|
|
{
|
|
if ((*q->function) (q->client, q->closure))
|
|
{
|
|
/* remove q from the list */
|
|
n = q->next; /* don't fetch until after func called */
|
|
if (p)
|
|
p->next = n;
|
|
else
|
|
workQueue = n;
|
|
xfree (q);
|
|
}
|
|
else
|
|
{
|
|
n = q->next; /* don't fetch until after func called */
|
|
p = q;
|
|
}
|
|
}
|
|
if (p)
|
|
workQueueLast = &p->next;
|
|
else
|
|
{
|
|
workQueueLast = &workQueue;
|
|
}
|
|
}
|
|
|
|
Bool
|
|
QueueWorkProc (function, client, closure)
|
|
Bool (*function)();
|
|
ClientPtr client;
|
|
pointer closure;
|
|
{
|
|
WorkQueuePtr q;
|
|
|
|
q = (WorkQueuePtr) xalloc (sizeof *q);
|
|
if (!q)
|
|
return FALSE;
|
|
q->function = function;
|
|
q->client = client;
|
|
q->closure = closure;
|
|
q->next = NULL;
|
|
*workQueueLast = q;
|
|
workQueueLast = &q->next;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Manage a queue of sleeping clients, awakening them
|
|
* when requested, by using the OS functions IgnoreClient
|
|
* and AttendClient. Note that this *ignores* the troubles
|
|
* with request data interleaving itself with events, but
|
|
* we'll leave that until a later time.
|
|
*/
|
|
|
|
typedef struct _SleepQueue {
|
|
struct _SleepQueue *next;
|
|
ClientPtr client;
|
|
Bool (*function)();
|
|
pointer closure;
|
|
} SleepQueueRec, *SleepQueuePtr;
|
|
|
|
static SleepQueuePtr sleepQueue = NULL;
|
|
|
|
Bool
|
|
ClientSleep (client, function, closure)
|
|
ClientPtr client;
|
|
Bool (*function)();
|
|
pointer closure;
|
|
{
|
|
SleepQueuePtr q;
|
|
|
|
q = (SleepQueuePtr) xalloc (sizeof *q);
|
|
if (!q)
|
|
return FALSE;
|
|
|
|
IgnoreClient (client);
|
|
q->next = sleepQueue;
|
|
q->client = client;
|
|
q->function = function;
|
|
q->closure = closure;
|
|
sleepQueue = q;
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
ClientSignal (client)
|
|
ClientPtr client;
|
|
{
|
|
SleepQueuePtr q;
|
|
|
|
for (q = sleepQueue; q; q = q->next)
|
|
if (q->client == client)
|
|
{
|
|
return QueueWorkProc (q->function, q->client, q->closure);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
ClientWakeup (client)
|
|
ClientPtr client;
|
|
{
|
|
SleepQueuePtr q, *prev;
|
|
|
|
prev = &sleepQueue;
|
|
while ((q = *prev))
|
|
{
|
|
if (q->client == client)
|
|
{
|
|
*prev = q->next;
|
|
xfree (q);
|
|
if (!client->clientGone)
|
|
AttendClient (client);
|
|
break;
|
|
}
|
|
prev = &q->next;
|
|
}
|
|
}
|
|
|
|
Bool
|
|
ClientIsAsleep (client)
|
|
ClientPtr client;
|
|
{
|
|
SleepQueuePtr q;
|
|
|
|
for (q = sleepQueue; q; q = q->next)
|
|
if (q->client == client)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef __UNIXOS2__
|
|
/* This code is duplicated from XLibInt.c, because the same problems with
|
|
* the drive letter as in clients also exist in the server
|
|
* Unfortunately the standalone servers don't link against libX11
|
|
*/
|
|
|
|
char *__XOS2RedirRoot(char *fname)
|
|
{
|
|
/* This adds a further redirection by allowing the ProjectRoot
|
|
* to be prepended by the content of the envvar X11ROOT.
|
|
* This is for the purpose to move the whole X11 stuff to a different
|
|
* disk drive.
|
|
* The feature was added despite various environment variables
|
|
* because not all file opens respect them.
|
|
*/
|
|
static char redirname[300]; /* enough for long filenames */
|
|
char *root;
|
|
|
|
/* if name does not start with /, assume it is not root-based */
|
|
if (fname==0 || !(fname[0]=='/' || fname[0]=='\\'))
|
|
return fname;
|
|
|
|
root = (char*)getenv("X11ROOT");
|
|
if (root==0 ||
|
|
(fname[1]==':' && isalpha(fname[0]) ||
|
|
(strlen(fname)+strlen(root)+2) > 300))
|
|
return fname;
|
|
sprintf(redirname,"%s%s",root,fname);
|
|
return redirname;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
LBXReadAtomsFile (server)
|
|
XServerPtr server;
|
|
{
|
|
FILE *f;
|
|
char buf[256], *p;
|
|
int len;
|
|
|
|
if (!atomsFile)
|
|
return;
|
|
|
|
while (server->atom_control_count)
|
|
xfree(server->atom_control[--server->atom_control_count].name);
|
|
xfree(server->atom_control);
|
|
server->atom_control = NULL;
|
|
min_keep_prop_size = DEF_KEEP_PROP_SIZE;
|
|
|
|
#ifdef __UNIXOS2__
|
|
atomsFile = (char*)__XOS2RedirRoot(atomsFile);
|
|
#endif
|
|
if (!(f = fopen (atomsFile, "r"))) {
|
|
ErrorF ("Could not load atom control file: %s\n", atomsFile);
|
|
return;
|
|
}
|
|
|
|
while (fgets (buf, 256, f))
|
|
if (*buf != '!' && *buf != 0 && *buf != '\n')
|
|
server->atom_control_count++;
|
|
|
|
if (!server->atom_control_count) {
|
|
fclose(f);
|
|
return;
|
|
}
|
|
|
|
server->atom_control = (AtomControlPtr) xalloc (server->atom_control_count *
|
|
sizeof(AtomControlRec));
|
|
|
|
server->atom_control_count = 0;
|
|
|
|
if (!server->atom_control) {
|
|
fclose(f);
|
|
return;
|
|
}
|
|
|
|
fseek (f, 0, 0);
|
|
|
|
while (fgets (buf, 256, f))
|
|
{
|
|
if (*buf == '!' || *buf == 0 || *buf == '\n')
|
|
continue;
|
|
|
|
len = strlen(buf);
|
|
if (buf[len - 1] == '\n')
|
|
buf[--len] = 0;
|
|
p = buf;
|
|
if (*p == 'z') {
|
|
do {
|
|
p++;
|
|
} while (*p == ' ' || *p == '\t');
|
|
min_keep_prop_size = atoi(p);
|
|
continue;
|
|
}
|
|
server->atom_control[server->atom_control_count].flags = 0;
|
|
while (*p && *p != ' ' && *p != '\t') {
|
|
switch (*p) {
|
|
case 'i':
|
|
server->atom_control[server->atom_control_count].flags
|
|
|= AtomPreInternFlag;
|
|
break;
|
|
case 'n':
|
|
server->atom_control[server->atom_control_count].flags
|
|
|= AtomNoCacheFlag;
|
|
break;
|
|
case 'w':
|
|
server->atom_control[server->atom_control_count].flags
|
|
|= AtomWMCacheFlag;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "bad atom control: %c\n", *p);
|
|
break;
|
|
}
|
|
p++;
|
|
}
|
|
while (*p == ' ' || *p == '\t')
|
|
p++;
|
|
if (!*p)
|
|
continue;
|
|
len = strlen(p);
|
|
server->atom_control[server->atom_control_count].name =
|
|
(char *) xalloc(len + 1);
|
|
if (server->atom_control[server->atom_control_count].name) {
|
|
server->atom_control[server->atom_control_count].len = len;
|
|
strcpy(server->atom_control[server->atom_control_count].name, p);
|
|
server->atom_control_count++;
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
}
|