Blame synfig-osx/launcher/bundle-main.c

Carlos Lopez a09598
/* bundle-main.c -- X server launcher
Carlos Lopez a09598
   $Id: bundle-main.c,v 1.17 2003/09/11 00:17:10 jharper Exp $
Carlos Lopez a09598
Carlos Lopez a09598
   Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
Carlos Lopez a09598
Carlos Lopez a09598
   Permission is hereby granted, free of charge, to any person
Carlos Lopez a09598
   obtaining a copy of this software and associated documentation files
Carlos Lopez a09598
   (the "Software"), to deal in the Software without restriction,
Carlos Lopez a09598
   including without limitation the rights to use, copy, modify, merge,
Carlos Lopez a09598
   publish, distribute, sublicense, and/or sell copies of the Software,
Carlos Lopez a09598
   and to permit persons to whom the Software is furnished to do so,
Carlos Lopez a09598
   subject to the following conditions:
Carlos Lopez a09598
Carlos Lopez a09598
   The above copyright notice and this permission notice shall be
Carlos Lopez a09598
   included in all copies or substantial portions of the Software.
Carlos Lopez a09598
Carlos Lopez a09598
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Carlos Lopez a09598
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Carlos Lopez a09598
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Carlos Lopez a09598
   NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
Carlos Lopez a09598
   HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
Carlos Lopez a09598
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Carlos Lopez a09598
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Carlos Lopez a09598
   DEALINGS IN THE SOFTWARE.
Carlos Lopez a09598
Carlos Lopez a09598
   Except as contained in this notice, the name(s) of the above
Carlos Lopez a09598
   copyright holders shall not be used in advertising or otherwise to
Carlos Lopez a09598
   promote the sale, use or other dealings in this Software without
Carlos Lopez a09598
   prior written authorization.
Carlos Lopez a09598
Carlos Lopez a09598
   Parts of this file are derived from xdm, which has this copyright:
Carlos Lopez a09598
Carlos Lopez a09598
   Copyright 1988, 1998  The Open Group
Carlos Lopez a09598
Carlos Lopez a09598
   Permission to use, copy, modify, distribute, and sell this software
Carlos Lopez a09598
   and its documentation for any purpose is hereby granted without fee,
Carlos Lopez a09598
   provided that the above copyright notice appear in all copies and
Carlos Lopez a09598
   that both that copyright notice and this permission notice appear in
Carlos Lopez a09598
   supporting documentation.
Carlos Lopez a09598
Carlos Lopez a09598
   The above copyright notice and this permission notice shall be
Carlos Lopez a09598
   included in all copies or substantial portions of the Software.
Carlos Lopez a09598
Carlos Lopez a09598
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Carlos Lopez a09598
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Carlos Lopez a09598
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Carlos Lopez a09598
   NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY
Carlos Lopez a09598
   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
Carlos Lopez a09598
   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
Carlos Lopez a09598
   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Carlos Lopez a09598
Carlos Lopez a09598
   Except as contained in this notice, the name of The Open Group shall
Carlos Lopez a09598
   not be used in advertising or otherwise to promote the sale, use or
Carlos Lopez a09598
   other dealings in this Software without prior written authorization
Carlos Lopez a09598
   from The Open Group. */
Carlos Lopez a09598
Carlos Lopez a09598
#include <stdio.h></stdio.h>
Carlos Lopez a09598
#include <unistd.h></unistd.h>
Carlos Lopez a09598
#include <stdlib.h></stdlib.h>
Carlos Lopez a09598
#include <fcntl.h></fcntl.h>
Carlos Lopez a09598
#include <errno.h></errno.h>
Carlos Lopez a09598
#include <sys socket.h=""></sys>
Carlos Lopez a09598
#include <sys utsname.h=""></sys>
Carlos Lopez a09598
#include <ifaddrs.h></ifaddrs.h>
Carlos Lopez a09598
#include <netdb.h></netdb.h>
Carlos Lopez a09598
#include <netinet in.h=""></netinet>
Carlos Lopez a09598
#include <time.h></time.h>
Carlos Lopez a09598
#include <sys wait.h=""></sys>
Carlos Lopez a09598
#include <setjmp.h></setjmp.h>
Carlos Lopez a09598
#include <sys ioctl.h=""></sys>
Carlos Lopez a09598
Carlos Lopez a09598
#include <x11 xlib.h=""></x11>
Carlos Lopez a09598
#include <x11 xauth.h=""></x11>
Carlos Lopez a09598
Carlos Lopez a09598
#include <corefoundation corefoundation.h=""></corefoundation>
Carlos Lopez a09598
#include <systemconfiguration systemconfiguration.h=""></systemconfiguration>
Carlos Lopez a09598
Carlos Lopez a09598
#define X_SERVER "/usr/X11R6/bin/Xquartz"
Carlos Lopez a09598
#define XTERM_PATH "/usr/X11R6/bin/xterm"
Carlos Lopez a09598
#define WM_PATH "/usr/X11R6/bin/quartz-wm"
Carlos Lopez a09598
#define DEFAULT_XINITRC "/usr/X11R6/lib/X11/xinit/xinitrc"
Carlos Lopez a09598
#include <mach-o dyld.h=""></mach-o>
Carlos Lopez a09598
Carlos Lopez a09598
/* what xinit does */
Carlos Lopez a09598
#ifndef SHELL
Carlos Lopez a09598
# define SHELL "sh"
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#undef FALSE
Carlos Lopez a09598
#define FALSE 0
Carlos Lopez a09598
#undef TRUE
Carlos Lopez a09598
#define TRUE 1
Carlos Lopez a09598
Carlos Lopez a09598
#define MAX_DISPLAYS 64
Carlos Lopez a09598
Carlos Lopez a09598
static int server_pid = -1, client_pid = -1;
Carlos Lopez a09598
static int xinit_kills_server = FALSE;
Carlos Lopez a09598
static jmp_buf exit_continuation;
Carlos Lopez a09598
static const char *server_name = NULL;
Carlos Lopez a09598
static Display *server_dpy;
Carlos Lopez a09598
Carlos Lopez a09598
static char *auth_file;
Carlos Lopez a09598
Carlos Lopez a09598
typedef struct addr_list_struct addr_list;
Carlos Lopez a09598
Carlos Lopez a09598
struct addr_list_struct {
Carlos Lopez a09598
    addr_list *next;
Carlos Lopez a09598
    Xauth auth;
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez a09598
static addr_list *addresses;
Carlos Lopez a09598
Carlos Lopez a09598

Carlos Lopez a09598
/* Utility functions. */
Carlos Lopez a09598
Carlos Lopez a09598
/* Return the current host name. Matches what Xlib does. */
Carlos Lopez a09598
static char *
Carlos Lopez a09598
host_name (void)
Carlos Lopez a09598
{
Carlos Lopez a09598
#ifdef NEED_UTSNAME
Carlos Lopez a09598
    static struct utsname name;
Carlos Lopez a09598
Carlos Lopez a09598
    uname(&name);
Carlos Lopez a09598
Carlos Lopez a09598
    return name.nodename;
Carlos Lopez a09598
#else
Carlos Lopez a09598
    static char buf[100];
Carlos Lopez a09598
Carlos Lopez a09598
    gethostname(buf, sizeof(buf));
Carlos Lopez a09598
Carlos Lopez a09598
    return buf;
Carlos Lopez a09598
#endif
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static int
Carlos Lopez a09598
read_boolean_pref (CFStringRef name, int default_)
Carlos Lopez a09598
{
Carlos Lopez a09598
    int value;
Carlos Lopez a09598
    Boolean ok;
Carlos Lopez a09598
Carlos Lopez a09598
    value = CFPreferencesGetAppBooleanValue (name,
Carlos Lopez a09598
					     CFSTR ("com.apple.x11"), &ok);
Carlos Lopez a09598
    return ok ? value : default_;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static inline int
Carlos Lopez a09598
binary_equal (const void *a, const void *b, int length)
Carlos Lopez a09598
{
Carlos Lopez a09598
    return memcmp (a, b, length) == 0;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static inline void *
Carlos Lopez a09598
binary_dup (const void *a, int length)
Carlos Lopez a09598
{
Carlos Lopez a09598
    void *b = malloc (length);
Carlos Lopez a09598
    if (b != NULL)
Carlos Lopez a09598
	memcpy (b, a, length);
Carlos Lopez a09598
    return b;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static inline void
Carlos Lopez a09598
binary_free (void *data, int length)
Carlos Lopez a09598
{
Carlos Lopez a09598
    if (data != NULL)
Carlos Lopez a09598
	free (data);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598

Carlos Lopez a09598
/* Functions for managing the authentication entries. */
Carlos Lopez a09598
Carlos Lopez a09598
/* Returns true if something matching AUTH is in our list of auth items */
Carlos Lopez a09598
static int
Carlos Lopez a09598
check_auth_item (Xauth *auth)
Carlos Lopez a09598
{
Carlos Lopez a09598
    addr_list *a;
Carlos Lopez a09598
Carlos Lopez a09598
    for (a = addresses; a != NULL; a = a->next)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (a->auth.family == auth->family
Carlos Lopez a09598
	    && a->auth.address_length == auth->address_length
Carlos Lopez a09598
	    && binary_equal (a->auth.address, auth->address, auth->address_length)
Carlos Lopez a09598
	    && a->auth.number_length == auth->number_length
Carlos Lopez a09598
	    && binary_equal (a->auth.number, auth->number, auth->number_length)
Carlos Lopez a09598
	    && a->auth.name_length == auth->name_length
Carlos Lopez a09598
	    && binary_equal (a->auth.name, auth->name, auth->name_length))
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    return TRUE;
Carlos Lopez a09598
	}
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    return FALSE;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Add one item to our list of auth items. */
Carlos Lopez a09598
static void
Carlos Lopez a09598
add_auth_item (Xauth *auth)
Carlos Lopez a09598
{
Carlos Lopez a09598
    addr_list *a = malloc (sizeof (addr_list));
Carlos Lopez a09598
Carlos Lopez a09598
    a->auth.family = auth->family;
Carlos Lopez a09598
    a->auth.address_length = auth->address_length;
Carlos Lopez a09598
    a->auth.address = binary_dup (auth->address, auth->address_length);
Carlos Lopez a09598
    a->auth.number_length = auth->number_length;
Carlos Lopez a09598
    a->auth.number = binary_dup (auth->number, auth->number_length);
Carlos Lopez a09598
    a->auth.name_length = auth->name_length;
Carlos Lopez a09598
    a->auth.name = binary_dup (auth->name, auth->name_length);
Carlos Lopez a09598
    a->auth.data_length = auth->data_length;
Carlos Lopez a09598
    a->auth.data = binary_dup (auth->data, auth->data_length);
Carlos Lopez a09598
Carlos Lopez a09598
    a->next = addresses;
Carlos Lopez a09598
    addresses = a;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Free all allocated auth items. */
Carlos Lopez a09598
static void
Carlos Lopez a09598
free_auth_items (void)
Carlos Lopez a09598
{
Carlos Lopez a09598
    addr_list *a;
Carlos Lopez a09598
Carlos Lopez a09598
    while ((a = addresses) != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	addresses = a->next;
Carlos Lopez a09598
Carlos Lopez a09598
	binary_free (a->auth.address, a->auth.address_length);
Carlos Lopez a09598
	binary_free (a->auth.number, a->auth.number_length);
Carlos Lopez a09598
	binary_free (a->auth.name, a->auth.name_length);
Carlos Lopez a09598
	binary_free (a->auth.data, a->auth.data_length);
Carlos Lopez a09598
	free (a);
Carlos Lopez a09598
    }
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Add the unix domain auth item. */
Carlos Lopez a09598
static void
Carlos Lopez a09598
define_local (Xauth *auth)
Carlos Lopez a09598
{
Carlos Lopez a09598
    char *host = host_name ();
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef DEBUG
Carlos Lopez a09598
    fprintf (stderr, "x11: hostname is %s\n", host);
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
    auth->family = FamilyLocal;
Carlos Lopez a09598
    auth->address_length = strlen (host);
Carlos Lopez a09598
    auth->address = host;
Carlos Lopez a09598
Carlos Lopez a09598
    add_auth_item (auth);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Add the tcp auth item. */
Carlos Lopez a09598
static void
Carlos Lopez a09598
define_named (Xauth *auth, const char *name)
Carlos Lopez a09598
{
Carlos Lopez a09598
    struct ifaddrs *addrs, *ptr;
Carlos Lopez a09598
Carlos Lopez a09598
    if (getifaddrs (&addrs) != 0)
Carlos Lopez a09598
	return;
Carlos Lopez a09598
Carlos Lopez a09598
    for (ptr = addrs; ptr != NULL; ptr = ptr->ifa_next)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (ptr->ifa_addr->sa_family != AF_INET)
Carlos Lopez a09598
	    continue;
Carlos Lopez a09598
Carlos Lopez a09598
	auth->family = FamilyInternet;
Carlos Lopez a09598
	auth->address_length = sizeof (struct sockaddr_in);
Carlos Lopez a09598
	auth->address = (char *) &(((struct sockaddr_in *) ptr->ifa_addr)->sin_addr);
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef DEBUG
Carlos Lopez a09598
	fprintf (stderr, "x11: ipaddr is %d.%d.%d.%d\n",
Carlos Lopez a09598
		 (unsigned char) auth->address[0],
Carlos Lopez a09598
		 (unsigned char) auth->address[1],
Carlos Lopez a09598
		 (unsigned char) auth->address[2],
Carlos Lopez a09598
		 (unsigned char) auth->address[3]);
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
	add_auth_item (auth);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    freeifaddrs (addrs);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Parse the display number from NAME and add it to AUTH. */
Carlos Lopez a09598
static void
Carlos Lopez a09598
set_auth_number (Xauth *auth, const char *name)
Carlos Lopez a09598
{
Carlos Lopez a09598
    char *colon;
Carlos Lopez a09598
    char *dot, *number;
Carlos Lopez a09598
Carlos Lopez a09598
    colon = strrchr(name, ':');
Carlos Lopez a09598
    if (colon != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	colon++;
Carlos Lopez a09598
	dot = strchr(colon, '.');
Carlos Lopez a09598
Carlos Lopez a09598
	if (dot != NULL)
Carlos Lopez a09598
	    auth->number_length = dot - colon;
Carlos Lopez a09598
	else
Carlos Lopez a09598
	    auth->number_length = strlen (colon);
Carlos Lopez a09598
Carlos Lopez a09598
	number = malloc (auth->number_length + 1);
Carlos Lopez a09598
	if (number != NULL)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    strncpy (number, colon, auth->number_length);
Carlos Lopez a09598
	    number[auth->number_length] = '\0';
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    auth->number_length = 0;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	auth->number = number;
Carlos Lopez a09598
    }
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Put 128 bits of random data into DATA. If possible, it will be "high
Carlos Lopez a09598
   quality" */
Carlos Lopez a09598
static int
Carlos Lopez a09598
generate_mit_magic_cookie (char data[16])
Carlos Lopez a09598
{
Carlos Lopez a09598
    int fd, ret, i;
Carlos Lopez a09598
    long *ldata = (long *) data;
Carlos Lopez a09598
Carlos Lopez a09598
    fd = open ("/dev/random", O_RDONLY);
Carlos Lopez a09598
    if (fd > 0)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	ret = read (fd, data, 16);
Carlos Lopez a09598
	if (ret == 16)
Carlos Lopez a09598
	    return TRUE;
Carlos Lopez a09598
Carlos Lopez a09598
	close (fd);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    /* fall back to the usual crappy rng */
Carlos Lopez a09598
Carlos Lopez a09598
    srand48 (getpid () ^ time (NULL));
Carlos Lopez a09598
Carlos Lopez a09598
    for (i = 0; i < 4; i++)
Carlos Lopez a09598
	ldata[i] = lrand48 ();
Carlos Lopez a09598
Carlos Lopez a09598
    return TRUE;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* Create the keys we'll be using for the display named NAME. */
Carlos Lopez a09598
static int
Carlos Lopez a09598
make_auth_keys (const char *name)
Carlos Lopez a09598
{
Carlos Lopez a09598
    Xauth auth;
Carlos Lopez a09598
    char key[16];
Carlos Lopez a09598
Carlos Lopez a09598
    if (auth_file == NULL)
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    auth.name = "MIT-MAGIC-COOKIE-1";
Carlos Lopez a09598
    auth.name_length = strlen (auth.name);
Carlos Lopez a09598
Carlos Lopez a09598
    if (!generate_mit_magic_cookie (key))
Carlos Lopez a09598
    {
Carlos Lopez a09598
	auth_file = NULL;
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    auth.data = key;
Carlos Lopez a09598
    auth.data_length = 16;
Carlos Lopez a09598
Carlos Lopez a09598
    set_auth_number (&auth, name);
Carlos Lopez a09598
Carlos Lopez a09598
    define_named (&auth, host_name ());
Carlos Lopez a09598
    define_local (&auth);
Carlos Lopez a09598
Carlos Lopez a09598
    free (auth.number);
Carlos Lopez a09598
Carlos Lopez a09598
    return TRUE;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* If ADD-ENTRIES is true, merge our auth entries into the existing
Carlos Lopez a09598
   Xauthority file. If ADD-ENTRIES is false, remove our entries. */
Carlos Lopez a09598
static int
Carlos Lopez a09598
write_auth_file (int add_entries)
Carlos Lopez a09598
{
Carlos Lopez a09598
    char *home, newname[1024];
Carlos Lopez a09598
    int fd, ret;
Carlos Lopez a09598
    FILE *new_fh, *old_fh;
Carlos Lopez a09598
    addr_list *addr;
Carlos Lopez a09598
    Xauth *auth;
Carlos Lopez a09598
Carlos Lopez a09598
    if (auth_file == NULL)
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    home = getenv ("HOME");
Carlos Lopez a09598
    if (home == NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	auth_file = NULL;
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    snprintf (newname, sizeof (newname), "%s/.XauthorityXXXXXX", home);
Carlos Lopez a09598
    mktemp (newname);
Carlos Lopez a09598
Carlos Lopez a09598
    if (XauLockAuth (auth_file, 1, 2, 10) != LOCK_SUCCESS)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	/* FIXME: do something here? */
Carlos Lopez a09598
Carlos Lopez a09598
	auth_file = NULL;
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    fd = open (newname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
Carlos Lopez a09598
    if (fd >= 0)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	new_fh = fdopen (fd, "w");
Carlos Lopez a09598
	if (new_fh != NULL)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    if (add_entries)
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		for (addr = addresses; addr != NULL; addr = addr->next)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		    XauWriteAuth (new_fh, &addr->auth);
Carlos Lopez a09598
		}
Carlos Lopez a09598
	    }
Carlos Lopez a09598
Carlos Lopez a09598
	    old_fh = fopen (auth_file, "r");
Carlos Lopez a09598
	    if (old_fh != NULL)
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		while ((auth = XauReadAuth (old_fh)) != NULL)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		    if (!check_auth_item (auth))
Carlos Lopez a09598
			XauWriteAuth (new_fh, auth);
Carlos Lopez a09598
		    XauDisposeAuth (auth);
Carlos Lopez a09598
		}
Carlos Lopez a09598
		fclose (old_fh);
Carlos Lopez a09598
	    }
Carlos Lopez a09598
Carlos Lopez a09598
	    fclose (new_fh);
Carlos Lopez a09598
	    unlink (auth_file);
Carlos Lopez a09598
Carlos Lopez a09598
	    ret = rename (newname, auth_file);
Carlos Lopez a09598
Carlos Lopez a09598
	    if (ret != 0)
Carlos Lopez a09598
		auth_file = NULL;
Carlos Lopez a09598
Carlos Lopez a09598
	    XauUnlockAuth (auth_file);
Carlos Lopez a09598
	    return ret == 0;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	close (fd);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    XauUnlockAuth (auth_file);
Carlos Lopez a09598
    auth_file = NULL;
Carlos Lopez a09598
    return FALSE;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598

Carlos Lopez a09598
/* Subprocess management functions. */
Carlos Lopez a09598
Carlos Lopez a09598
static int
Carlos Lopez a09598
start_server (char **xargv)
Carlos Lopez a09598
{
Carlos Lopez a09598
    int child;
Carlos Lopez a09598
Carlos Lopez a09598
    child = fork ();
Carlos Lopez a09598
Carlos Lopez a09598
    switch (child)
Carlos Lopez a09598
    {
Carlos Lopez a09598
    case -1:				/* error */
Carlos Lopez a09598
	perror ("fork");
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    case 0:				/* child */
Carlos Lopez a09598
	execv (X_SERVER, xargv);
Carlos Lopez a09598
	perror ("Couldn't exec " X_SERVER);
Carlos Lopez a09598
	_exit (1);
Carlos Lopez a09598
Carlos Lopez a09598
    default:				/* parent */
Carlos Lopez a09598
	server_pid = child;
Carlos Lopez a09598
	return TRUE;
Carlos Lopez a09598
    }
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static int
Carlos Lopez a09598
wait_for_server (void)
Carlos Lopez a09598
{
Carlos Lopez a09598
    int count = 100;
Carlos Lopez a09598
Carlos Lopez a09598
    while (count-- > 0)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	int status;
Carlos Lopez a09598
Carlos Lopez a09598
	server_dpy = XOpenDisplay (server_name);
Carlos Lopez a09598
	if (server_dpy != NULL)
Carlos Lopez a09598
	    return TRUE;
Carlos Lopez a09598
Carlos Lopez a09598
	if (waitpid (server_pid, &status, WNOHANG) == server_pid)
Carlos Lopez a09598
	    return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
	sleep (1);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    return FALSE;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static int
Carlos Lopez a09598
start_client (void)
Carlos Lopez a09598
{
Carlos Lopez a09598
    int child;
Carlos Lopez a09598
Carlos Lopez a09598
    child = fork ();
Carlos Lopez a09598
Carlos Lopez a09598
    switch (child)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	char *tem, buf[1024];
Carlos Lopez a09598
Carlos Lopez a09598
    case -1:				/* error */
Carlos Lopez a09598
	perror ("fork");
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    case 0:				/* child */
Carlos Lopez a09598
	/* cd $HOME */
Carlos Lopez a09598
	tem = getenv ("HOME");
Carlos Lopez a09598
	if (tem != NULL)
Carlos Lopez a09598
	    chdir (tem);
Carlos Lopez a09598
Carlos Lopez a09598
	/* Setup environment */
Carlos Lopez a09598
Carlos Lopez a09598
	setenv ("DISPLAY", server_name, TRUE);
Carlos Lopez a09598
	tem = getenv ("PATH");
Carlos Lopez a09598
	if (tem != NULL && tem[0] != NULL)
Carlos Lopez a09598
	    snprintf (buf, sizeof (buf), "%s:/usr/X11R6/bin", tem);
Carlos Lopez a09598
	else
Carlos Lopez a09598
	    snprintf (buf, sizeof (buf), "/bin:/usr/bin:/usr/X11R6/bin");
Carlos Lopez a09598
	setenv ("PATH", buf, TRUE);
Carlos Lopez a09598
Carlos Lopez a09598
#if 1
Carlos Lopez a09598
	setenv("GTK_USE_XFT","1",0);
Carlos Lopez a09598
	system(WM_PATH " &");
Carlos Lopez a09598
	execl("/usr/local/bin/synfigstudio","/usr/local/bin/synfigstudio",NULL);
Carlos Lopez a09598
Carlos Lopez a09598
#else
Carlos Lopez a09598
	/* First look for .xinitrc in user's home directory. */
Carlos Lopez a09598
Carlos Lopez a09598
	tem = getenv ("HOME");
Carlos Lopez a09598
	if (tem != NULL)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    snprintf (buf, sizeof (buf), "%s/.xinitrc", tem);
Carlos Lopez a09598
	    if (access (buf, R_OK) == 0)
Carlos Lopez a09598
		execlp (SHELL, SHELL, buf, NULL);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	/* Then try the default xinitrc in the lib directory. */
Carlos Lopez a09598
Carlos Lopez a09598
	if (access (DEFAULT_XINITRC, R_OK) == 0)
Carlos Lopez a09598
	    execlp (SHELL, SHELL, DEFAULT_XINITRC, NULL);
Carlos Lopez a09598
Carlos Lopez a09598
	/* Then fallback to hardcoding an xterm and the window manager. */
Carlos Lopez a09598
Carlos Lopez a09598
	system (XTERM_PATH " &");
Carlos Lopez a09598
	execl (WM_PATH, WM_PATH, NULL);
Carlos Lopez a09598
	
Carlos Lopez a09598
#endif
Carlos Lopez a09598
	perror ("exec");
Carlos Lopez a09598
	_exit (1);
Carlos Lopez a09598
Carlos Lopez a09598
    default:				/* parent */
Carlos Lopez a09598
	client_pid = child;
Carlos Lopez a09598
	return TRUE;
Carlos Lopez a09598
    }
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static void
Carlos Lopez a09598
sigchld_handler (int sig)
Carlos Lopez a09598
{
Carlos Lopez a09598
    int pid, status;
Carlos Lopez a09598
Carlos Lopez a09598
again:
Carlos Lopez a09598
    pid = waitpid (WAIT_ANY, &status, WNOHANG);
Carlos Lopez a09598
Carlos Lopez a09598
    if (pid > 0)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (pid == server_pid)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    server_pid = -1;
Carlos Lopez a09598
Carlos Lopez a09598
	    if (client_pid >= 0)
Carlos Lopez a09598
		kill (client_pid, SIGTERM);
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else if (pid == client_pid)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    client_pid = -1;
Carlos Lopez a09598
Carlos Lopez a09598
	    if (server_pid >= 0 && xinit_kills_server)
Carlos Lopez a09598
		kill (server_pid, SIGTERM);
Carlos Lopez a09598
	}
Carlos Lopez a09598
	goto again;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    if (server_pid == -1 && client_pid == -1)
Carlos Lopez a09598
	longjmp (exit_continuation, 1);
Carlos Lopez a09598
Carlos Lopez a09598
    signal (SIGCHLD, sigchld_handler);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598

Carlos Lopez a09598
/* Server utilities. */
Carlos Lopez a09598
Carlos Lopez a09598
static Boolean
Carlos Lopez a09598
display_exists_p (int number)
Carlos Lopez a09598
{
Carlos Lopez a09598
    char buf[64];
Carlos Lopez a09598
    void *conn;
Carlos Lopez a09598
    char *fullname = NULL;
Carlos Lopez a09598
    int idisplay, iscreen;
Carlos Lopez a09598
    char *conn_auth_name, *conn_auth_data;
Carlos Lopez a09598
    int conn_auth_namelen, conn_auth_datalen;
Carlos Lopez a09598
Carlos Lopez a09598
    extern void *_X11TransConnectDisplay ();
Carlos Lopez a09598
    extern void _XDisconnectDisplay ();
Carlos Lopez a09598
Carlos Lopez a09598
    /* Since connecting to the display waits for a few seconds if the
Carlos Lopez a09598
       display doesn't exist, check for trivial non-existence - if the
Carlos Lopez a09598
       socket in /tmp exists or not.. (note: if the socket exists, the
Carlos Lopez a09598
       server may still not, so we need to try to connect in that case..) */
Carlos Lopez a09598
Carlos Lopez a09598
    sprintf (buf, "/tmp/.X11-unix/X%d", number);
Carlos Lopez a09598
    if (access (buf, F_OK) != 0)
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    /* This is a private function that we shouldn't really be calling,
Carlos Lopez a09598
       but it's the best way to see if the server exists (without
Carlos Lopez a09598
       needing to hold the necessary authentication to use it) */
Carlos Lopez a09598
Carlos Lopez a09598
    sprintf (buf, ":%d", number);
Carlos Lopez a09598
    conn = _X11TransConnectDisplay (buf, &fullname, &idisplay, &iscreen,
Carlos Lopez a09598
				    &conn_auth_name, &conn_auth_namelen,
Carlos Lopez a09598
				    &conn_auth_data, &conn_auth_datalen);
Carlos Lopez a09598
    if (conn == NULL)
Carlos Lopez a09598
	return FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    _XDisconnectDisplay (conn);
Carlos Lopez a09598
    return TRUE;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598

Carlos Lopez a09598
/* Monitoring when the system's ip addresses change. */
Carlos Lopez a09598
Carlos Lopez a09598
static Boolean pending_timer;
Carlos Lopez a09598
Carlos Lopez a09598
static void
Carlos Lopez a09598
timer_callback (CFRunLoopTimerRef timer, void *info)
Carlos Lopez a09598
{
Carlos Lopez a09598
    pending_timer = FALSE;
Carlos Lopez a09598
Carlos Lopez a09598
    /* Update authentication names. Need to write .Xauthority file first
Carlos Lopez a09598
       without the existing entries, then again with the new entries.. */
Carlos Lopez a09598
Carlos Lopez a09598
    write_auth_file (FALSE);
Carlos Lopez a09598
Carlos Lopez a09598
    free_auth_items ();
Carlos Lopez a09598
    make_auth_keys (server_name);
Carlos Lopez a09598
Carlos Lopez a09598
    write_auth_file (TRUE);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* This function is called when the system's ip addresses may have changed. */
Carlos Lopez a09598
static void
Carlos Lopez a09598
ipaddr_callback (SCDynamicStoreRef store, CFArrayRef changed_keys, void *info)
Carlos Lopez a09598
{
Carlos Lopez a09598
    if (auth_file != NULL && !pending_timer)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	CFRunLoopTimerRef timer;
Carlos Lopez a09598
Carlos Lopez a09598
	timer = CFRunLoopTimerCreate (NULL, CFAbsoluteTimeGetCurrent () + 1.0,
Carlos Lopez a09598
				      0.0, 0, 0, timer_callback, NULL);
Carlos Lopez a09598
	CFRunLoopAddTimer (CFRunLoopGetCurrent (), timer,
Carlos Lopez a09598
			   kCFRunLoopDefaultMode);
Carlos Lopez a09598
	CFRelease (timer);
Carlos Lopez a09598
Carlos Lopez a09598
	pending_timer = TRUE;
Carlos Lopez a09598
    }
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* This code adapted from "Living in a Dynamic TCP/IP Environment" technote. */
Carlos Lopez a09598
static Boolean
Carlos Lopez a09598
install_ipaddr_source (void)
Carlos Lopez a09598
{
Carlos Lopez a09598
    CFRunLoopSourceRef source = NULL;
Carlos Lopez a09598
Carlos Lopez a09598
    SCDynamicStoreContext context = {0};
Carlos Lopez a09598
    SCDynamicStoreRef ref;
Carlos Lopez a09598
Carlos Lopez a09598
    ref = SCDynamicStoreCreate (NULL,
Carlos Lopez a09598
				CFSTR ("AddIPAddressListChangeCallbackSCF"),
Carlos Lopez a09598
				ipaddr_callback, &context);
Carlos Lopez a09598
Carlos Lopez a09598
    if (ref != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	const void *keys[2];
Carlos Lopez a09598
Carlos Lopez a09598
	/* This should tell us when any IPV4 address changes */
Carlos Lopez a09598
	keys[0] = (SCDynamicStoreKeyCreateNetworkServiceEntity
Carlos Lopez a09598
		   (NULL, kSCDynamicStoreDomainState,
Carlos Lopez a09598
		    kSCCompAnyRegex, kSCEntNetIPv4));
Carlos Lopez a09598
Carlos Lopez a09598
	/* This should tell us when the hostname(s) change */
Carlos Lopez a09598
	keys[1] = SCDynamicStoreKeyCreateHostNames (NULL);
Carlos Lopez a09598
Carlos Lopez a09598
	if (keys[0] != NULL && keys[1] != NULL)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    CFArrayRef pattern_array;
Carlos Lopez a09598
Carlos Lopez a09598
	    pattern_array = CFArrayCreate (NULL, keys, 2,
Carlos Lopez a09598
					   &kCFTypeArrayCallBacks);
Carlos Lopez a09598
Carlos Lopez a09598
	    if (pattern_array != NULL)
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		SCDynamicStoreSetNotificationKeys (ref, NULL, pattern_array);
Carlos Lopez a09598
		source = SCDynamicStoreCreateRunLoopSource (NULL, ref, 0);
Carlos Lopez a09598
Carlos Lopez a09598
		CFRelease (pattern_array);
Carlos Lopez a09598
	    }
Carlos Lopez a09598
Carlos Lopez a09598
	    if (keys[0] != NULL)
Carlos Lopez a09598
		CFRelease (keys[0]);
Carlos Lopez a09598
	    if (keys[1] != NULL)
Carlos Lopez a09598
		CFRelease (keys[1]);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	CFRelease (ref); 
Carlos Lopez a09598
   }
Carlos Lopez a09598
Carlos Lopez a09598
    if (source != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	CFRunLoopAddSource (CFRunLoopGetCurrent (),
Carlos Lopez a09598
			    source, kCFRunLoopDefaultMode);
Carlos Lopez a09598
	CFRelease (source);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    return source != NULL;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598

Carlos Lopez a09598
/* Entrypoint. */
Carlos Lopez a09598
int
Carlos Lopez a09598
main (int argc, char **argv)
Carlos Lopez a09598
{
Carlos Lopez a09598
    char **xargv;
Carlos Lopez a09598
    int i, j;
Carlos Lopez a09598
    int fd;
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
    xargv = alloca (sizeof (char *) * (argc + 32));
Carlos Lopez a09598
Carlos Lopez a09598
    if (!read_boolean_pref (CFSTR ("no_auth"), FALSE))
Carlos Lopez a09598
	auth_file = XauFileName ();
Carlos Lopez a09598
Carlos Lopez a09598
    /* The standard X11 behaviour is for the server to quit when the first
Carlos Lopez a09598
       client exits. But it can be useful for debugging (and to mimic our
Carlos Lopez a09598
       behaviour in the beta releases) to not do that. */
Carlos Lopez a09598
Carlos Lopez a09598
    xinit_kills_server = read_boolean_pref (CFSTR ("xinit_kills_server"), TRUE);
Carlos Lopez a09598
Carlos Lopez a09598
    for (i = 1; i < argc; i++)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (argv[i][0] == ':')
Carlos Lopez a09598
	    server_name = argv[i];
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    if (server_name == NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	static char name[8];
Carlos Lopez a09598
Carlos Lopez a09598
	/* No display number specified, so search for the first unused.
Carlos Lopez a09598
Carlos Lopez a09598
	   There's a big old race condition here if two servers start at
Carlos Lopez a09598
	   the same time, but that's fairly unlikely. We could create
Carlos Lopez a09598
	   lockfiles or something, but that's seems more likely to cause
Carlos Lopez a09598
	   problems than the race condition itself.. */
Carlos Lopez a09598
Carlos Lopez a09598
	for (i = 2; i < MAX_DISPLAYS; i++)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    if (!display_exists_p (i))
Carlos Lopez a09598
		break;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if (i == MAX_DISPLAYS)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    fprintf (stderr, "%s: couldn't allocate a display number", argv[0]);
Carlos Lopez a09598
	    exit (1);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	sprintf (name, ":%d", i);
Carlos Lopez a09598
	server_name = name;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    if (auth_file != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	/* Create new Xauth keys and add them to the .Xauthority file */
Carlos Lopez a09598
Carlos Lopez a09598
	make_auth_keys (server_name);
Carlos Lopez a09598
	write_auth_file (TRUE);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    /* Construct our new argv */
Carlos Lopez a09598
Carlos Lopez a09598
    i = j = 0;
Carlos Lopez a09598
Carlos Lopez a09598
    xargv[i++] = argv[j++];
Carlos Lopez a09598
Carlos Lopez a09598
    if (auth_file != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	xargv[i++] = "-auth";
Carlos Lopez a09598
	xargv[i++] = auth_file;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    /* By default, don't listen on tcp sockets if Xauth is disabled. */
Carlos Lopez a09598
Carlos Lopez a09598
    if (read_boolean_pref (CFSTR ("nolisten_tcp"), auth_file == NULL))
Carlos Lopez a09598
    {
Carlos Lopez a09598
	xargv[i++] = "-nolisten";
Carlos Lopez a09598
	xargv[i++] = "tcp";
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    while (j < argc)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (argv[j++][0] != ':')
Carlos Lopez a09598
	    xargv[i++] = argv[j-1];
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    xargv[i++] = (char *) server_name;
Carlos Lopez a09598
    xargv[i++] = NULL;
Carlos Lopez a09598
Carlos Lopez a09598
    /* Detach from any controlling terminal and connect stdin to /dev/null */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef TIOCNOTTY
Carlos Lopez a09598
    fd = open ("/dev/tty", O_RDONLY);
Carlos Lopez a09598
    if (fd != -1)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	ioctl (fd, TIOCNOTTY, 0);
Carlos Lopez a09598
	close (fd);
Carlos Lopez a09598
    }
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
    fd = open ("/dev/null", O_RDWR, 0);
Carlos Lopez a09598
    if (fd >= 0)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	dup2 (fd, 0);
Carlos Lopez a09598
	if (fd > 0)
Carlos Lopez a09598
	    close (fd);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    if (!start_server (xargv))
Carlos Lopez a09598
	return 1;
Carlos Lopez a09598
Carlos Lopez a09598
    if (!wait_for_server ())
Carlos Lopez a09598
    {
Carlos Lopez a09598
	kill (server_pid, SIGTERM);
Carlos Lopez a09598
	return 1;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    if (!start_client ())
Carlos Lopez a09598
    {
Carlos Lopez a09598
	kill (server_pid, SIGTERM);
Carlos Lopez a09598
	return 1;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    signal (SIGCHLD, sigchld_handler);
Carlos Lopez a09598
Carlos Lopez a09598
	if (NSIsSymbolNameDefined("_ASKInitialize"))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		NSSymbol *symbol = NSLookupAndBindSymbol("_ASKInitialize");
Carlos Lopez a09598
		if (symbol)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			void (*initializeASKFunc)(void) = NSAddressOfSymbol(symbol);
Carlos Lopez a09598
			if (initializeASKFunc)
Carlos Lopez a09598
			{
Carlos Lopez a09598
				initializeASKFunc();
Carlos Lopez a09598
			}
Carlos Lopez a09598
			else
Carlos Lopez a09598
				return 666;
Carlos Lopez a09598
		}
Carlos Lopez a09598
		else return 667;
Carlos Lopez a09598
	}else
Carlos Lopez a09598
	return 668;
Carlos Lopez a09598
Carlos Lopez a09598
    if (setjmp (exit_continuation) == 0)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (install_ipaddr_source ())
Carlos Lopez a09598
	    CFRunLoopRun ();
Carlos Lopez a09598
	else
Carlos Lopez a09598
	    while (1) pause ();
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    signal (SIGCHLD, SIG_IGN);
Carlos Lopez a09598
Carlos Lopez a09598
    if (auth_file != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	/* Remove our Xauth keys */
Carlos Lopez a09598
Carlos Lopez a09598
	write_auth_file (FALSE);
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    free_auth_items ();
Carlos Lopez a09598
Carlos Lopez a09598
    return 0;
Carlos Lopez a09598
}