server.c 33.9 KB
Newer Older
Martin Peterson's avatar
Martin Peterson committed
1
/* GDM - The Gnome Display Manager
2
 * Copyright (C) 1999, 2000 Martin K. Petersen <mkp@mkp.net>
Martin Peterson's avatar
Martin Peterson committed
3 4 5 6 7 8 9 10
 *
 * 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 2 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
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Martin Peterson's avatar
Martin Peterson committed
12 13 14 15
 * 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, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Martin Peterson's avatar
Martin Peterson committed
17 18 19 20 21
 */

/* This file contains functions for controlling local X servers */

#include <config.h>
22
#include <libgnome/libgnome.h>
Martin Peterson's avatar
Martin Peterson committed
23
#include <stdio.h>
24
#include <unistd.h>
Martin Peterson's avatar
Martin Peterson committed
25 26
#include <stdlib.h>
#include <fcntl.h>
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
27 28
#include <pwd.h>
#include <grp.h>
Martin Peterson's avatar
Martin Peterson committed
29 30 31 32 33
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <strings.h>
#include <signal.h>
34
#include <syslog.h>
Martin Peterson's avatar
Martin Peterson committed
35
#include <errno.h>
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
36
#include <time.h>
37
#include <ctype.h>
Martin Peterson's avatar
Martin Peterson committed
38 39
#include <X11/Xlib.h>

40 41
#include <vicious.h>

Martin Peterson's avatar
Martin Peterson committed
42
#include "gdm.h"
1's avatar
1 committed
43 44 45 46 47
#include "server.h"
#include "misc.h"
#include "xdmcp.h"
#include "display.h"
#include "auth.h"
48
#include "slave.h"
49
#include "getvt.h"
Martin Peterson's avatar
Martin Peterson committed
50

51 52
#define SERVER_WAIT_ALARM 10

Martin Peterson's avatar
Martin Peterson committed
53

1's avatar
1 committed
54
/* Local prototypes */
55
static void gdm_server_spawn (GdmDisplay *d, const char *vtarg);
56 57
static void gdm_server_usr1_handler (gint);
static void gdm_server_child_handler (gint);
58
static char * get_font_path (const char *display);
Martin Peterson's avatar
Martin Peterson committed
59

1's avatar
1 committed
60 61 62 63
/* Configuration options */
extern gchar *GdmDisplayInit;
extern gchar *GdmServAuthDir;
extern gchar *GdmLogDir;
64
extern gchar *GdmStandardXServer;
65
extern gboolean GdmXdmcp;
66
extern gboolean GdmDisallowTCP;
67
extern gint high_display_num;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
68
extern pid_t extra_process;
69
extern int extra_status;
70
extern int gdm_in_signal;
Martin Peterson's avatar
Martin Peterson committed
71

1's avatar
1 committed
72
/* Global vars */
73
static GdmDisplay *d = NULL;
74 75
static gboolean server_signal_notified = FALSE;
static int server_signal_pipe[2];
Martin Peterson's avatar
Martin Peterson committed
76

77 78 79
static void do_server_wait (GdmDisplay *d);
static gboolean setup_server_wait (GdmDisplay *d);

80
void
81
gdm_server_whack_lockfile (GdmDisplay *disp)
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
{
	    char buf[256];

	    /* X seems to be sometimes broken with its lock files and
	       doesn't seem to remove them always, and if you manage
	       to get into the weird state where the old pid now
	       corresponds to some new pid, X will just die with
	       a stupid error. */

	    /* Yes there could be a race here if another X server starts
	       at this exact instant.  Oh well such is life.  Very unlikely
	       to happen though as we should really be the only ones
	       trying to start X servers, and we aren't starting an
	       X server on this display yet. */

	    /* if lock file exists and it is our process, whack it! */
	    g_snprintf (buf, sizeof (buf), "/tmp/.X%d-lock", disp->dispnum);
99
	    IGNORE_EINTR (unlink (buf));
100

101 102 103
	    /* whack the unix socket as well */
	    g_snprintf (buf, sizeof (buf),
			"/tmp/.X11-unix/X%d", disp->dispnum);
104
	    IGNORE_EINTR (unlink (buf));
105 106 107
}


Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
108 109 110 111 112
/* Wipe cookie files */
void
gdm_server_wipe_cookies (GdmDisplay *disp)
{
	if ( ! ve_string_empty (disp->authfile))
113
		IGNORE_EINTR (unlink (disp->authfile));
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
114 115 116
	g_free (disp->authfile);
	disp->authfile = NULL;
	if ( ! ve_string_empty (disp->authfile_gdm))
117
		IGNORE_EINTR (unlink (disp->authfile_gdm));
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
118 119 120 121
	g_free (disp->authfile_gdm);
	disp->authfile_gdm = NULL;
}

122 123
static Jmp_buf reinitjmp;

124 125 126 127 128 129 130 131
/* ignore handlers */
static int
ignore_xerror_handler (Display *disp, XErrorEvent *evt)
{
	return 0;
}

static int
132
jumpback_xioerror_handler (Display *disp)
133
{
134
	Longjmp (reinitjmp, 1);
135 136
}

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#ifdef HAVE_FBCONSOLE
#define FBCONSOLE "/usr/openwin/bin/fbconsole"

static void
gdm_exec_fbconsole(GdmDisplay *disp)
{
        pid_t pid;
        char *argv[6];

        argv[0] = FBCONSOLE;
        argv[1] = "-d";
        argv[2] = disp->name;
        argv[3] = NULL;

        pid = fork ();
        if (pid == 0) {
                gdm_close_all_descriptors (0 /* from */, -1 /* except */, -1 /* except2 */)
;
                IGNORE_EINTR (execv (argv[0], argv));
        }
        if (pid == -1) {
                gdm_error (_("Can not start fallback console"));
        }
}
#endif

163 164 165 166 167 168 169 170
/**
 * gdm_server_reinit:
 * @disp: Pointer to a GdmDisplay structure
 *
 * Reinit the display, basically sends a HUP signal
 * but only if the display exists
 */

171
gboolean
172 173
gdm_server_reinit (GdmDisplay *disp)
{
174
	if (disp == NULL)
175
		return FALSE;
176

177 178 179 180 181 182 183
	if (disp->servpid <= 0) {
		/* Kill our connection if one existed, likely to result
		 * in some bizzaro error right now */
		if (disp->dsp != NULL) {
			XCloseDisplay (disp->dsp);
			disp->dsp = NULL;
		}
184
		return FALSE;
185
	}
186

187 188
	gdm_debug ("gdm_server_reinit: Server for %s is about to be reinitialized!", disp->name);

189 190
	if ( ! setup_server_wait (disp))
		return FALSE;
191

192
	d->servstat = SERVER_PENDING;
193

194
	if (disp->dsp != NULL) {
195 196 197 198 199 200
		/* static because of the Setjmp */
		static int (*old_xerror_handler)(Display *, XErrorEvent *) = NULL;
		static int (*old_xioerror_handler)(Display *) = NULL;

		old_xerror_handler = NULL;
		old_xioerror_handler = NULL;
201

202 203
		/* Do note the interaction of this Setjmp and the signal
	   	   handlers and the Setjmp in slave.c */
204

205
		/* Long live Setjmp, DIE DIE DIE XSetIOErrorHandler */
206

207 208 209 210 211
		if (Setjmp (reinitjmp) == 0)  {
			/* come here and we'll whack the server and wait to get
			   an xio error */
			old_xerror_handler = XSetErrorHandler (ignore_xerror_handler);
			old_xioerror_handler = XSetIOErrorHandler (jumpback_xioerror_handler);
212

213 214 215 216 217 218
			/* Now whack the server with a SIGHUP */
			gdm_sigchld_block_push ();
			if (disp->servpid > 1)
				kill (disp->servpid, SIGHUP);
			else
				d->servstat = SERVER_DEAD;
219
			gdm_sigchld_block_pop ();
220

221 222 223 224
			/* the server is dead, weird */
			if (disp->dsp != NULL) {
				XCloseDisplay (disp->dsp);
				disp->dsp = NULL;
225 226
			}
		}
227 228 229 230 231 232 233 234 235 236 237
		/* no more display */
		disp->dsp = NULL;
		XSetErrorHandler (old_xerror_handler);
		XSetIOErrorHandler (old_xioerror_handler);
	} else {
		/* Now whack the server with a SIGHUP */
		gdm_sigchld_block_push ();
		if (disp->servpid > 1)
			kill (disp->servpid, SIGHUP);
		else
			d->servstat = SERVER_DEAD;
238 239
		gdm_sigchld_block_pop ();
	}
240 241 242 243

	/* Wait for the SIGUSR1 */
	do_server_wait (d);

244 245 246 247
	if (d->servstat == SERVER_RUNNING) {
#ifdef HAVE_FBCONSOLE
		gdm_exec_fbconsole(d);
#endif
248
		return TRUE;
249
        } else {
250
		return FALSE;
251
	}
252 253
}

254 255 256 257 258 259 260 261
/**
 * gdm_server_stop:
 * @disp: Pointer to a GdmDisplay structure
 *
 * Stops a local X server, but only if it exists
 */

void
262
gdm_server_stop (GdmDisplay *disp)
263
{
264 265
    static gboolean waiting_for_server = FALSE;

266
    if (disp == NULL)
267 268
	return;

269
    /* Kill our connection if one existed */
270
    if (disp->dsp != NULL) {
271 272 273
	    /* on XDMCP servers first kill everything in sight */
	    if (disp->type == TYPE_XDMCP)
		    gdm_server_whack_clients (d);
274 275
	    XCloseDisplay (disp->dsp);
	    disp->dsp = NULL;
276
    }
277 278 279 280 281 282

    if (disp->servpid <= 0)
	    return;

    gdm_debug ("gdm_server_stop: Server for %s going down!", disp->name);

283 284
    disp->servstat = SERVER_DEAD;

285
    if (disp->servpid > 0) {
286
	    pid_t servpid;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
287

288 289
	    gdm_debug ("gdm_server_stop: Killing server pid %d",
		       (int)disp->servpid);
290

291
	    /* avoid SIGCHLD race */
292
	    gdm_sigchld_block_push ();
293
	    servpid = disp->servpid;
294 295 296 297 298 299 300 301 302 303 304 305 306 307

	    if (waiting_for_server) {
		    gdm_error ("gdm_server_stop: Some problem killing server, whacking with SIGKILL");
		    if (disp->servpid > 1)
			    kill (disp->servpid, SIGKILL);

	    } else {
		    if (disp->servpid > 1 &&
			kill (disp->servpid, SIGTERM) == 0) {
			    waiting_for_server = TRUE;
			    ve_waitpid_no_signal (disp->servpid, 0, 0);
			    waiting_for_server = FALSE;
		    }
	    }
308 309
	    disp->servpid = 0;

310 311
	    gdm_sigchld_block_pop ();

312
	    gdm_server_whack_lockfile (disp);
313

314
	    gdm_debug ("gdm_server_stop: Server pid %d dead", (int)servpid);
315 316
    }

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
317
    gdm_server_wipe_cookies (disp);
318 319

    gdm_slave_whack_temp_auth_file ();
320 321
}

322 323
static gboolean
busy_ask_user (GdmDisplay *disp)
324 325
{
    /* if we have "open" we can talk to the user */
326
    if (access (EXPANDED_LIBEXECDIR "/gdmopen", X_OK) == 0) {
327
	    char *error = g_strdup_printf
328 329 330 331
		    (_("There already appears to be an X server "
		       "running on display %s.  Should I try another "
		       "display number?  If you answer no, I will "
		       "attempt to start the server on %s again.%s"),
332
		     disp->name,
333 334
		     disp->name,
#ifdef __linux__
335 336 337 338
		     _("  (You can change consoles by pressing Ctrl-Alt "
		       "plus a function key, such as Ctrl-Alt-F7 to go "
		       "to console 7.  X servers usually run on consoles "
		       "7 and higher.)")
339 340 341 342 343
#else /* ! __linux__ */
		     /* no info for non linux users */
		     ""
#endif /* __linux__ */
		     );
344 345 346 347
	    gboolean ret = TRUE;
	    /* default ret to TRUE */
	    if ( ! gdm_text_yesno_dialog (error, &ret))
		    ret = TRUE;
348
	    g_free (error);
349
	    return ret;
350
    } else {
351 352
	    /* Well we'll just try another display number */
	    return TRUE;
353 354 355
    }
}

356
/* Checks only output, no XFree86 v4 logfile */
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
static gboolean
display_xnest_no_connect (GdmDisplay *disp)
{
	char *logname = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL);
	FILE *fp;
	char buf[256];

	fp = fopen (logname, "r");
	g_free (logname);

	if (fp == NULL)
		return FALSE;

	while (fgets (buf, sizeof (buf), fp) != NULL) {
		/* Note: this is probably XFree86 specific, and perhaps even
		 * version 3 specific (I don't have xfree v4 to test this),
		 * of course additions are welcome to make this more robust */
		if (strstr (buf, "Unable to open display \"") == buf) {
			gdm_error (_("Display '%s' cannot be opened by Xnest"),
				   ve_sure_string (disp->xnest_disp));
			fclose (fp);
			return TRUE;
		}
	}

	fclose (fp);
	return FALSE;
}

386 387 388 389 390 391 392 393 394 395 396 397 398 399
static gboolean
display_busy (GdmDisplay *disp)
{
	char *logname = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL);
	FILE *fp;
	char buf[256];

	fp = fopen (logname, "r");
	g_free (logname);

	if (fp == NULL)
		return FALSE;

	while (fgets (buf, sizeof (buf), fp) != NULL) {
400
		/* Note: this is probably XFree86 specific */
401
		if (strstr (buf, "Server is already active for display")
402
		    == buf) {
403 404
			gdm_error (_("Display %s is busy. There is another "
				     "X server running already."),
405 406 407 408 409 410 411 412 413 414
				   disp->name);
			fclose (fp);
			return TRUE;
		}
	}

	fclose (fp);
	return FALSE;
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
/* if we find 'Log file: "foo"' switch fp to foo and
   return TRUE */
/* Note: assumes buf is of size 256 and is writable */ 
static gboolean
open_another_logfile (char buf[256], FILE **fp)
{
	if (strncmp (&buf[5], "Log file: \"", strlen ("Log file: \"")) == 0) {
		FILE *ffp;
		char *fname = &buf[5+strlen ("Log file: \"")];
		char *p = strchr (fname, '"');
		if (p == NULL)
			return FALSE;
		*p = '\0';
		ffp = fopen (fname, "r");
		if (ffp == NULL)
			return FALSE;
		fclose (*fp);
		*fp = ffp;
		return TRUE;
	}
	return FALSE;
}

438 439 440 441 442 443
static int
display_vt (GdmDisplay *disp)
{
	char *logname = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL);
	FILE *fp;
	char buf[256];
444
	gboolean switched = FALSE;
445 446 447 448 449 450 451 452 453

	fp = fopen (logname, "r");
	g_free (logname);

	if (fp == NULL)
		return FALSE;

	while (fgets (buf, sizeof (buf), fp) != NULL) {
		int vt;
454 455 456 457 458 459 460 461 462 463 464 465 466
		char *p;

		if ( ! switched &&
		     /* this is XFree v4 specific */
		    open_another_logfile (buf, &fp)) {
			switched = TRUE;
			continue;
		} 
		/* Note: this is probably XFree86 specific (works with
		 * both v3 and v4 though */
		p = strstr (buf, "using VT number ");
		if (p != NULL &&
		    sscanf (p, "using VT number %d", &vt) == 1) {
467 468 469 470 471 472 473 474
			fclose (fp);
			return vt;
		}
	}
	fclose (fp);
	return -1;
}

475 476
static struct sigaction old_svr_wait_chld;
static sigset_t old_svr_wait_mask;
477

478 479
static gboolean
setup_server_wait (GdmDisplay *d)
480
{
481 482
    struct sigaction usr1, chld;
    sigset_t mask;
483

484
    if (pipe (server_signal_pipe) != 0) {
485
	    gdm_error (_("%s: Error opening a pipe: %s"),
486
		       "setup_server_wait", strerror (errno));
487 488 489 490
	    return FALSE; 
    }
    server_signal_notified = FALSE;

Martin Peterson's avatar
Martin Peterson committed
491 492
    /* Catch USR1 from X server */
    usr1.sa_handler = gdm_server_usr1_handler;
493
    usr1.sa_flags = SA_RESTART;
494
    sigemptyset (&usr1.sa_mask);
495

496
    if (sigaction (SIGUSR1, &usr1, NULL) < 0) {
497 498
	    gdm_error (_("%s: Error setting up %s signal handler: %s"),
		       "gdm_server_start", "USR1", strerror (errno));
499 500
	    IGNORE_EINTR (close (server_signal_pipe[0]));
	    IGNORE_EINTR (close (server_signal_pipe[1]));
501
	    return FALSE;
Martin Peterson's avatar
Martin Peterson committed
502
    }
1's avatar
1 committed
503 504 505

    /* Catch CHLD from X server */
    chld.sa_handler = gdm_server_child_handler;
506
    chld.sa_flags = SA_RESTART|SA_NOCLDSTOP;
1's avatar
1 committed
507
    sigemptyset (&chld.sa_mask);
508

509
    if (sigaction (SIGCHLD, &chld, &old_svr_wait_chld) < 0) {
510 511 512
	    gdm_error (_("%s: Error setting up %s signal handler: %s"),
		       "gdm_server_start", "CHLD", strerror (errno));
	    gdm_signal_ignore (SIGUSR1);
513 514
	    IGNORE_EINTR (close (server_signal_pipe[0]));
	    IGNORE_EINTR (close (server_signal_pipe[1]));
515
	    return FALSE;
1's avatar
1 committed
516 517
    }

518 519 520 521
    /* Set signal mask */
    sigemptyset (&mask);
    sigaddset (&mask, SIGUSR1);
    sigaddset (&mask, SIGCHLD);
522
    sigprocmask (SIG_UNBLOCK, &mask, &old_svr_wait_mask);
523

524 525
    return TRUE;
}
526

527 528 529
static void
do_server_wait (GdmDisplay *d)
{
530
    /* Wait for X server to send ready signal */
531
    if (d->servstat == SERVER_PENDING) {
532 533 534 535 536
	    if (d->server_uid != 0 && ! d->handled) {
		    /* FIXME: If not handled, we just don't know, so
		     * just wait a few seconds and hope things just work,
		     * fortunately there is no such case yet and probably
		     * never will, but just for code anality's sake */
537
		    gdm_sleep_no_signal (5);
538
	    } else if (d->server_uid != 0) {
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
539 540
		    int i;

541 542 543
		    /* FIXME: This is not likely to work in reinit,
		       but we never reinit Xnest servers nowdays,
		       so that's fine */
544

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
545 546 547 548
		    /* if we're running the server as a non-root, we can't
		     * use USR1 of course, so try openning the display 
		     * as a test, but the */

549 550 551 552 553
		    /* just in case it's set */
		    ve_unsetenv ("XAUTHORITY");

		    gdm_auth_set_local_auth (d);

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
554 555
		    for (i = 0;
			 d->dsp == NULL &&
556
			 d->servstat == SERVER_PENDING &&
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
557 558 559 560
			 i < SERVER_WAIT_ALARM;
			 i++) {
			    d->dsp = XOpenDisplay (d->name);
			    if (d->dsp == NULL)
561
				    gdm_sleep_no_signal (1);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
562 563 564 565 566
			    else
				    d->servstat = SERVER_RUNNING;
		    }
		    if (d->dsp == NULL &&
			/* Note: we could have still gotten a SIGCHLD */
567
			d->servstat == SERVER_PENDING) {
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
568 569 570
			    d->servstat = SERVER_TIMEOUT;
		    }
	    } else {
571
		    time_t t = time (NULL);
572

573
		    gdm_debug ("do_server_wait: Before mainloop waiting for server");
574 575

		    do {
576
			    fd_set rfds;
577 578 579 580 581
			    struct timeval tv;

			    /* Wait up to SERVER_WAIT_ALARM seconds. */
			    tv.tv_sec = MAX (1, SERVER_WAIT_ALARM - (time(NULL) - t));
			    tv.tv_usec = 0;
582 583 584 585

			    FD_ZERO (&rfds);
			    FD_SET (server_signal_pipe[0], &rfds);

586
			    if (select (server_signal_pipe[0]+1, &rfds, NULL, NULL, &tv) > 0) {
587 588
				    char buf[4];
				    /* read the Yay! */
589
				    IGNORE_EINTR (read (server_signal_pipe[0], buf, 4));
590
			    }
591 592 593 594 595 596 597 598 599 600
			    if ( ! server_signal_notified &&
				t + SERVER_WAIT_ALARM < time (NULL)) {
				    gdm_debug ("do_server_wait: Server timeout");
				    d->servstat = SERVER_TIMEOUT;
				    server_signal_notified = TRUE;
			    }
			    if (d->servpid <= 1) {
				    d->servstat = SERVER_ABORT;
				    server_signal_notified = TRUE;
			    }
601 602
		    } while ( ! server_signal_notified);

603
		    gdm_debug ("gdm_server_start: After mainloop waiting for server");
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
604 605
	    }
    }
606

607
    /* restore default handlers */
608
    gdm_signal_ignore (SIGUSR1);
609 610 611
    sigaction (SIGCHLD, &old_svr_wait_chld, NULL);
    sigprocmask (SIG_SETMASK, &old_svr_wait_mask, NULL);

612 613
    IGNORE_EINTR (close (server_signal_pipe[0]));
    IGNORE_EINTR (close (server_signal_pipe[1]));
614 615 616 617

    if (d->servpid <= 1) {
	    d->servstat = SERVER_ABORT;
    }
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
}

/**
 * gdm_server_start:
 * @disp: Pointer to a GdmDisplay structure
 *
 * Starts a local X server. Handles retries and fatal errors properly.
 */

gboolean
gdm_server_start (GdmDisplay *disp, gboolean treat_as_flexi,
		  int min_flexi_disp, int flexi_retries)
{
    int flexi_disp = 20;
    char *vtarg = NULL;
    int vtfd = -1, vt = -1;
    
    if (disp == NULL)
	    return FALSE;

    d = disp;

    /* if an X server exists, wipe it */
    gdm_server_stop (d);

    /* First clear the VT number */
    if (d->type == TYPE_LOCAL ||
	d->type == TYPE_FLEXI) {
	    d->vt = -1;
	    gdm_slave_send_num (GDM_SOP_VT_NUM, -1);
    }

    if (SERVER_IS_FLEXI (d) ||
	treat_as_flexi) {
	    flexi_disp = gdm_get_free_display
		    (MAX (high_display_num + 1, min_flexi_disp) /* start */,
		     d->server_uid /* server uid */);

	    g_free (d->name);
	    d->name = g_strdup_printf (":%d", flexi_disp);
	    d->dispnum = flexi_disp;

	    gdm_slave_send_num (GDM_SOP_DISP_NUM, flexi_disp);
    }


    gdm_debug ("gdm_server_start: %s", d->name);

    /* Create new cookie */
    if ( ! gdm_auth_secure_display (d)) 
	    return FALSE;
    gdm_slave_send_string (GDM_SOP_COOKIE, d->cookie);
    ve_setenv ("DISPLAY", d->name, TRUE);

    if ( ! setup_server_wait (d))
	    return FALSE;

    d->servstat = SERVER_DEAD;
676

677 678 679
    if (d->type == TYPE_LOCAL ||
	d->type == TYPE_FLEXI) {
	    vtarg = gdm_get_empty_vt_argument (&vtfd, &vt);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
680
    }
681

682 683 684 685 686 687 688
    /* fork X server process */
    gdm_server_spawn (d, vtarg);

    /* we can now use d->handled since that's set up above */

    do_server_wait (d);

689 690 691
    /* If we were holding a vt open for the server, close it now as it has
     * already taken the bait. */
    if (vtfd > 0)
692
	    IGNORE_EINTR (close (vtfd));
693

694
    switch (d->servstat) {
695

696
    case SERVER_TIMEOUT:
697
	    gdm_debug ("gdm_server_start: Temporary server failure (%s)", d->name);
698
	    break;
699

700 701
    case SERVER_ABORT:
	    gdm_debug ("gdm_server_start: Server %s died during startup!", d->name);
702 703
	    break;

704
    case SERVER_RUNNING:
1's avatar
1 committed
705
	    gdm_debug ("gdm_server_start: Completed %s!", d->name);
706

707 708
	    if (SERVER_IS_FLEXI (d))
		    gdm_slave_send_num (GDM_SOP_FLEXI_OK, 0 /* bogus */);
709 710
	    if (d->type == TYPE_LOCAL ||
		d->type == TYPE_FLEXI) {
711 712 713 714 715
		    if (vt >= 0)
			    d->vt = vt;

		    if (d->vt < 0)
			    d->vt = display_vt (d);
716 717 718
		    if (d->vt >= 0)
			    gdm_slave_send_num (GDM_SOP_VT_NUM, d->vt);
	    }
719

720 721 722 723
#ifdef HAVE_FBCONSOLE
            gdm_exec_fbconsole(d);
#endif

724
	    return TRUE;
725
    default:
726 727 728
	    break;
    }

729 730
    /* bad things are happening */
    if (d->servpid > 0) {
731 732
	    pid_t pid;

733 734
	    d->dsp = NULL;

735
	    gdm_sigchld_block_push ();
736 737
	    pid = d->servpid;
	    d->servpid = 0;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
738
	    if (pid > 1 &&
739
		kill (pid, SIGTERM) == 0)
740
		    ve_waitpid_no_signal (pid, NULL, 0);
741
	    gdm_sigchld_block_pop ();
742
	    
743
	    gdm_server_whack_lockfile (disp);
744
    }
745

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
746
    /* We will rebake cookies anyway, so wipe these */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
747
    gdm_server_wipe_cookies (disp);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
748

749 750 751 752 753 754 755
    if (disp->type == TYPE_FLEXI_XNEST &&
	display_xnest_no_connect (disp)) {
	    gdm_slave_send_num (GDM_SOP_FLEXI_ERR,
				5 /* Xnest can't connect */);
	    _exit (DISPLAY_REMANAGE);
    }

756 757 758 759 760
    /* if this was a busy fail, that is, there is already
     * a server on that display, we'll display an error and after
     * this we'll exit with DISPLAY_REMANAGE to try again if the
     * user wants to, or abort this display */
    if (display_busy (disp)) {
761 762
	    if (SERVER_IS_FLEXI (disp) ||
		treat_as_flexi) {
763 764 765 766
		    /* for flexi displays, try again a few times with different
		     * display numbers */
		    if (flexi_retries <= 0) {
			    /* Send X too busy */
767 768 769 770 771 772 773
			    gdm_error (_("%s: Cannot find a free "
					 "display number"),
				       "gdm_server_start");
			    if (SERVER_IS_FLEXI (disp)) {
				    gdm_slave_send_num (GDM_SOP_FLEXI_ERR,
							4 /* X too busy */);
			    }
774 775 776
			    /* eki eki */
			    _exit (DISPLAY_REMANAGE);
		    }
777 778
		    return gdm_server_start (d, treat_as_flexi,
					     flexi_disp + 1,
779 780
					     flexi_retries - 1);
	    } else {
781 782 783 784 785 786 787 788 789 790 791
		    if (busy_ask_user (disp)) {
			    gdm_error (_("%s: Display %s busy.  Trying "
					 "another display number."),
				       "gdm_server_start",
				       d->name);
			    d->busy_display = TRUE;
			    return gdm_server_start (d,
						     TRUE /* treat as flexi */,
						     high_display_num + 1,
						     flexi_retries - 1);
		    }
792 793
		    _exit (DISPLAY_REMANAGE);
	    }
794 795
    }

796
    _exit (DISPLAY_XFAILED);
797

798
    return FALSE;
799 800
}

801 802 803 804 805 806
/* Do things that require checking the log,
 * we really do need to get called a bit later, after all init is done
 * as things aren't written to disk before that */
void
gdm_server_checklog (GdmDisplay *disp)
{
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
807 808 809 810 811 812 813
	if (d->vt < 0 &&
	    (d->type == TYPE_LOCAL ||
	     d->type == TYPE_FLEXI)) {
		d->vt = display_vt (d);
		if (d->vt >= 0)
			gdm_slave_send_num (GDM_SOP_VT_NUM, d->vt);
	}
814
}
815

816 817 818 819 820 821 822 823 824
/* somewhat safer rename (safer if the log dir is unsafe), may in fact
   lose the file though, it guarantees that a is gone, but not that
   b exists */
static void
safer_rename (const char *a, const char *b)
{
	errno = 0;
	if (link (a, b) < 0) {
		if (errno == EEXIST) {
825
			IGNORE_EINTR (unlink (a));
826 827
			return;
		} 
828
		IGNORE_EINTR (unlink (b));
829 830
		/* likely this system doesn't support hard links */
		rename (a, b);
831
		IGNORE_EINTR (unlink (a));
832 833
		return;
	}
834
	IGNORE_EINTR (unlink (a));
835 836
}

837 838 839 840 841 842 843 844 845 846 847
static void
rotate_logs (const char *dname)
{
	/* I'm too lazy to write a loop damnit */
	char *fname4 = g_strconcat (GdmLogDir, "/", dname, ".log.4", NULL);
	char *fname3 = g_strconcat (GdmLogDir, "/", dname, ".log.3", NULL);
	char *fname2 = g_strconcat (GdmLogDir, "/", dname, ".log.2", NULL);
	char *fname1 = g_strconcat (GdmLogDir, "/", dname, ".log.1", NULL);
	char *fname = g_strconcat (GdmLogDir, "/", dname, ".log", NULL);

	/* Rotate the logs (keep 4 last) */
848
	IGNORE_EINTR (unlink (fname4));
849 850 851 852
	safer_rename (fname3, fname4);
	safer_rename (fname2, fname3);
	safer_rename (fname1, fname2);
	safer_rename (fname, fname1);
853 854 855 856 857 858 859 860

	g_free (fname4);
	g_free (fname3);
	g_free (fname2);
	g_free (fname1);
	g_free (fname);
}

861

862 863
char **
gdm_server_resolve_command_line (GdmDisplay *disp,
864
				 gboolean resolve_flags,
865
				 const char *vtarg)
866 867 868 869 870
{
	char *bin;
	char **argv;
	int len;
	int i;
871
	gboolean gotvtarg = FALSE;
872
	gboolean query_in_arglist = FALSE;
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898

	bin = ve_first_word (disp->command);
	if (bin == NULL) {
		gdm_error (_("Invalid server command '%s'"), disp->command);
		argv = ve_split (GdmStandardXServer);
	} else if (bin[0] != '/') {
		GdmXServer *svr = gdm_find_x_server (bin);
		if (svr == NULL) {
			gdm_error (_("Server name '%s' not found, "
				     "using standard server"), bin);
			argv = ve_split (GdmStandardXServer);
		} else {
			char **svr_command =
				ve_split (ve_sure_string (svr->command));
			argv = ve_split (disp->command);
			if (argv[0] == NULL || argv[1] == NULL) {
				g_strfreev (argv);
				argv = svr_command;
			} else {
				char **old_argv = argv;
				argv = ve_vector_merge (svr_command,
							&old_argv[1]);
				g_strfreev (svr_command);
				g_strfreev (old_argv);
			} 

899
			if (resolve_flags) {
900 901
				/* Setup the handled function */
				disp->handled = svr->handled;
902 903 904 905 906 907
				/* never make use_chooser FALSE,
				   it may have been set temporarily for
				   us by the master */
				if (svr->chooser)
					disp->use_chooser = TRUE;
			}
908 909 910 911 912
		}
	} else {
		argv = ve_split (disp->command);
	}

913 914 915 916 917 918 919 920 921
	for (len = 0; argv != NULL && argv[len] != NULL; len++) {
		char *arg = argv[len];
		/* HACK! Not to add vt argument to servers that already force
		 * allocation.  Mostly for backwards compat only */
		if (strncmp (arg, "vt", 2) == 0 &&
		    isdigit (arg[2]) &&
		    (arg[3] == '\0' ||
		     (isdigit (arg[3]) && arg[4] == '\0')))
			gotvtarg = TRUE;
922 923 924
		if (strcmp (arg, "-query") == 0 ||
		    strcmp (arg, "-indirect") == 0)
			query_in_arglist = TRUE;
925
	}
926

927
	argv = g_renew (char *, argv, len + 10);
928 929 930 931 932
	for (i = len - 1; i >= 1; i--) {
		argv[i+1] = argv[i];
	}
	/* server number is the FIRST argument, before any others */
	argv[1] = g_strdup (disp->name);
933
	len++;
934

935
	if (disp->authfile != NULL) {
936 937
		argv[len++] = g_strdup ("-auth");
		argv[len++] = g_strdup (disp->authfile);
938 939
	}

940 941 942 943 944 945 946 947 948
	if (resolve_flags && disp->chosen_hostname) {
		/* this display is NOT handled */
		disp->handled = FALSE;
		/* never ever ever use chooser here */
		disp->use_chooser = FALSE;
		/* run just one session */
		argv[len++] = g_strdup ("-terminate");
		argv[len++] = g_strdup ("-query");
		argv[len++] = g_strdup (disp->chosen_hostname);
949 950 951 952 953 954
		query_in_arglist = TRUE;
	}

	if (resolve_flags && GdmDisallowTCP && ! query_in_arglist) {
		argv[len++] = g_strdup ("-nolisten");
		argv[len++] = g_strdup ("tcp");
955 956
	}

957 958 959 960 961 962 963
	if (vtarg != NULL &&
	    ! gotvtarg) {
		argv[len++] = g_strdup (vtarg);
	}

	argv[len++] = NULL;

964 965 966 967 968
	g_free (bin);

	return argv;
}

1's avatar
1 committed
969 970 971 972 973
/**
 * gdm_server_spawn:
 * @disp: Pointer to a GdmDisplay structure
 *
 * forks an actual X server process
974 975 976
 *
 * Note that we can only use d->handled once we call this function
 * since otherwise the server might not yet be looked up yet.
1's avatar
1 committed
977 978
 */

979
static void 
980
gdm_server_spawn (GdmDisplay *d, const char *vtarg)
981
{
982
    struct sigaction ign_signal;
983
    sigset_t mask;
984
    gchar **argv = NULL;
985
    char *logfile;
986
    int logfd;
987
    char *command;
988
    pid_t pid;
989

990
    if (d == NULL ||
991
	ve_string_empty (d->command)) {
992 993
	    return;
    }
994

995
    d->servstat = SERVER_PENDING;
996

997 998
    gdm_sigchld_block_push ();

999 1000
    /* eek, some previous copy, just wipe it */
    if (d->servpid > 0) {
1001 1002
	    pid_t pid = d->servpid;
	    d->servpid = 0;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1003 1004
	    if (pid > 1 &&
		kill (pid, SIGTERM) == 0)
1005
		    ve_waitpid_no_signal (pid, NULL, 0);
1006
    }
1007

1008
    /* Figure out the server command */
1009
    argv = gdm_server_resolve_command_line (d,
1010
					    TRUE /* resolve flags */,
1011
					    vtarg);
1012

1013
    command = g_strjoinv (" ", argv);
1014

1015
    /* Fork into two processes. Parent remains the gdm process. Child
1016
     * becomes the X server. */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1017

1018 1019
    gdm_sigterm_block_push ();
    pid = d->servpid = fork ();
1020 1021
    if (pid == 0)
	    gdm_unset_signals ();
1022 1023
    gdm_sigterm_block_pop ();
    gdm_sigchld_block_pop ();
1024
    
1025
    switch (pid) {
Martin Peterson's avatar
Martin Peterson committed
1026 1027
	
    case 0:
1028 1029
	/* the pops whacked mask again */
        gdm_unset_signals ();
1030

1031 1032
	closelog ();

1033
	/* close things */
1034
	gdm_close_all_descriptors (0 /* from */, -1 /* except */, -1 /* except2 */);
1035

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1036 1037
	/* No error checking here - if it's messed the best response
         * is to ignore & try to continue */
1038 1039 1040
	gdm_open_dev_null (O_RDONLY); /* open stdin - fd 0 */
	gdm_open_dev_null (O_RDWR); /* open stdout - fd 1 */
	gdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1041

1042 1043
	openlog ("gdm", LOG_PID, LOG_DAEMON);

1044 1045 1046
	/* Rotate the X server logs */
	rotate_logs (d->name);

1047
        /* Log all output from spawned programs to a file */
1048
	logfile = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL);
1049
	IGNORE_EINTR (unlink (logfile));
1050
	logfd = open (logfile, O_CREAT|O_TRUNC|O_WRONLY|O_EXCL, 0644);
1051 1052

	if (logfd != -1) {
1053 1054
		IGNORE_EINTR (dup2 (logfd, 1));
		IGNORE_EINTR (dup2 (logfd, 2));
1055
        } else {
1056 1057
		gdm_error (_("%s: Could not open logfile for display %s!"),
			   "gdm_server_spawn", d->name);
1058 1059
	}

1060
	
1061 1062 1063 1064
	/* The X server expects USR1/TTIN/TTOU to be SIG_IGN */
	ign_signal.sa_handler = SIG_IGN;
	ign_signal.sa_flags = SA_RESTART;
	sigemptyset (&ign_signal.sa_mask);
1065

1066 1067 1068 1069 1070 1071 1072
	if (d->server_uid == 0) {
		/* only set this if we can actually listen */
		if (sigaction (SIGUSR1, &ign_signal, NULL) < 0) {
			gdm_error (_("%s: Error setting %s to %s"),
				   "gdm_server_spawn", "USR1", "SIG_IGN");
			_exit (SERVER_ABORT);
		}
Martin Peterson's avatar
Martin Peterson committed
1073
	}
1074
	if (sigaction (SIGTTIN, &ign_signal, NULL) < 0) {
1075 1076
		gdm_error (_("%s: Error setting %s to %s"),
			   "gdm_server_spawn", "TTIN", "SIG_IGN");
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1077
		_exit (SERVER_ABORT);
1078 1079
	}
	if (sigaction (SIGTTOU, &ign_signal, NULL) < 0) {
1080 1081
		gdm_error (_("%s: Error setting %s to %s"),
			   "gdm_server_spawn", "TTOU", "SIG_IGN");
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1082
		_exit (SERVER_ABORT);
1083
	}
1084

1085 1086
	/* And HUP and TERM are at SIG_DFL from gdm_unset_signals,
	   we also have an empty mask and all that fun stuff */
1087

1088 1089
	/* unblock signals (especially HUP/TERM/USR1) so that we
	 * can control the X server */
1090
	sigemptyset (&mask);
1091
	sigprocmask (SIG_SETMASK, &mask, NULL);
1092

1093
	if (d->type == TYPE_FLEXI_XNEST) {
1094
		char *font_path = NULL;
1095
		ve_setenv ("DISPLAY", d->xnest_disp, TRUE);
1096
		if (d->xnest_auth_file != NULL)
1097
			ve_setenv ("XAUTHORITY", d->xnest_auth_file, TRUE);
1098
		else
1099
			ve_unsetenv ("XAUTHORITY");
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113

		/* Add -fp with the current font path, but only if not
		 * already among the arguments */
		if (strstr (command, "-fp") == NULL)
			font_path = get_font_path (d->xnest_disp);
		if (font_path != NULL) {
			int argc = ve_vector_len (argv);
			argv = g_renew (char *, argv, argc + 3);
			argv[argc++] = "-fp";
			argv[argc++] = font_path;
			argv[argc++] = NULL;
			command = g_strconcat (command, " -fp ",
					       font_path, NULL);
		}
1114 1115
	}

1116
	if (argv[0] == NULL) {
1117 1118 1119 1120 1121 1122
		gdm_error (_("%s: Empty server command for display %s"),
			   "gdm_server_spawn",
			   d->name);
		_exit (SERVER_ABORT);
	}

1123
	gdm_debug ("gdm_server_spawn: '%s'", command);
1124 1125
	
	setpgid (0, 0);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137

	if (d->server_uid != 0) {
		struct passwd *pwent;
		pwent = getpwuid (d->server_uid);
		if (pwent == NULL) {
			gdm_error (_("%s: Server was to be spawned by uid %d but "
				     "that user doesn't exist"),
				   "gdm_server_spawn",
				   (int)d->server_uid);
			_exit (SERVER_ABORT);
		}
		if (pwent->pw_dir != NULL &&
1138
		    g_file_test (pwent->pw_dir, G_FILE_TEST_EXISTS))
1139
			ve_setenv ("HOME", pwent->pw_dir, TRUE);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1140
		else
1141
			ve_setenv ("HOME", "/", TRUE); /* Hack */
1142 1143
		ve_setenv ("SHELL", pwent->pw_shell, TRUE);
		ve_unsetenv ("MAIL");
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

		if (setgid (pwent->pw_gid) < 0)  {
			gdm_error (_("%s: Couldn't set groupid to %d"), 
				   "gdm_server_spawn", (int)pwent->pw_gid);
			_exit (SERVER_ABORT);
		}

		if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) {
			gdm_error (_("%s: initgroups() failed for %s"),
				   "gdm_server_spawn", pwent->pw_name);
			_exit (SERVER_ABORT);
		}

		if (setuid (d->server_uid) < 0)  {
			gdm_error (_("%s: Couldn't set userid to %d"),
				   "gdm_server_spawn", (int)d->server_uid);
			_exit (SERVER_ABORT);
		}
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
	} else {
		gid_t groups[1] = { 0 };
		if (setgid (0) < 0)  {
			gdm_error (_("%s: Couldn't set groupid to 0"), 
				   "gdm_server_spawn");
			/* Don't error out, it's not fatal, if it fails we'll
			 * just still be */
		}
		/* this will get rid of any suplementary groups etc... */
		setgroups (1, groups);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1172 1173
	}

1174
	IGNORE_EINTR (execv (argv[0], argv));
1175
	
1176 1177
	gdm_error (_("%s: Xserver not found: %s"), 
		   "gdm_server_spawn", command);
1178
	
1179
	_exit (SERVER_ABORT);
Martin Peterson's avatar
Martin Peterson committed
1180 1181
	
    case -1:
1182
	g_strfreev (argv);
1183
	g_free (command);
1184 1185
	gdm_error (_("%s: Can't fork Xserver process!"),
		   "gdm_server_spawn");
1186
	d->servpid = 0;
1187
	d->servstat = SERVER_DEAD;
1188

Martin Peterson's avatar
Martin Peterson committed
1189 1190 1191
	break;
	
    default:
1192
	g_strfreev (argv);
1193
	g_free (command);
1194 1195
	gdm_debug ("%s: Forked server on pid %d", 
		   "gdm_server_spawn", (int)pid);
Martin Peterson's avatar
Martin Peterson committed
1196 1197 1198 1199
	break;
    }
}

1's avatar
1 committed
1200 1201 1202 1203 1204 1205 1206
/**
 * gdm_server_usr1_handler:
 * @sig: Signal value
 *
 * Received when the server is ready to accept connections
 */

1207
static void
1208
gdm_server_usr1_handler (gint sig)
Martin Peterson's avatar
Martin Peterson committed
1209
{
1210 1211
    gdm_in_signal++;

1212 1213
    d->servstat = SERVER_RUNNING; /* Server ready to accept connections */
    d->starttime = time (NULL);
1214

1215 1216
    gdm_debug ("gdm_server_usr1_handler: Got SIGUSR1, server running");

1217 1218
    server_signal_notified = TRUE;
    /* this will quit the select */
1219
    IGNORE_EINTR (write (server_signal_pipe[1], "Yay!", 4));
1220 1221

    gdm_in_signal--;
Martin Peterson's avatar
Martin Peterson committed
1222 1223 1224
}


1's avatar
1 committed
1225 1226 1227 1228 1229 1230 1231
/**
 * gdm_server_child_handler:
 * @sig: Signal value
 *
 * Received when server died during startup
 */

1232
static void 
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1233
gdm_server_child_handler (int signal)
Martin Peterson's avatar
Martin Peterson committed
1234
{
1235 1236
	gdm_in_signal++;

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1237
	gdm_debug ("gdm_server_child_handler: Got SIGCHLD");
1238

1239 1240 1241
	/* go to the main child handler */
	gdm_slave_child_handler (signal);

1242
	/* this will quit the select */
1243
	IGNORE_EINTR (write (server_signal_pipe[1], "Yay!", 4));
1244 1245

	gdm_in_signal--;
Martin Peterson's avatar
Martin Peterson committed
1246 1247 1248
}


1's avatar
1 committed
1249 1250 1251 1252 1253 1254 1255 1256
/**
 * gdm_server_alloc:
 * @id: Local display number
 * @command: Command line for starting the X server
 *
 * Allocate display structure for a local X server
 */

Martin Peterson's avatar
Martin Peterson committed
1257
GdmDisplay * 
1258
gdm_server_alloc (gint id, const gchar *command)
Martin Peterson's avatar
Martin Peterson committed
1259
{
1260 1261
    gchar hostname[1024];
    GdmDisplay *d;
1262
    
1263
    hostname[1023] = '\0';
1264
    if (gethostname (hostname, 1023) == -1)
1265
	    strcmp (hostname, "localhost.localdomain");
1266

1267 1268
    d = g_new0 (GdmDisplay, 1);

1269
    d->authfile = NULL;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1270
    d->authfile_gdm = NULL;
1271 1272 1273
    d->auths = NULL;
    d->userauth = NULL;
    d->command = g_strdup (command);
Martin Peterson's avatar
Martin Peterson committed
1274
    d->cookie = NULL;
Gregory Leblanc's avatar
Gregory Leblanc committed
1275
    d->dispstat = DISPLAY_UNBORN;
Martin Peterson's avatar
Martin Peterson committed
1276
    d->greetpid = 0;
1277
    d->name = g_strdup_printf (":%d", id);  
1278
    d->hostname = g_strdup (hostname);
1279 1280
    /* Not really used for not XDMCP */
    memset (&(d->addr), 0, sizeof (struct in_addr));
1281
    d->dispnum = id;
Martin Peterson's avatar
Martin Peterson committed
1282 1283 1284 1285
    d->servpid = 0;
    d->servstat = SERVER_DEAD;
    d->sesspid = 0;
    d->slavepid = 0;
1286
    d->type = TYPE_LOCAL;
1287
    d->console = TRUE;
Martin Peterson's avatar
Martin Peterson committed
1288 1289 1290
    d->sessionid = 0;
    d->acctime = 0;
    d->dsp = NULL;
1291 1292
    d->screenx = 0; /* xinerama offset */
    d->screeny = 0;
1293

1294 1295
    d->handled = TRUE;

1296 1297
    d->vt = -1;

1298 1299
    d->x_servers_order = -1;

1300
    d->last_loop_start_time = 0;
1301 1302 1303
    d->last_start_time = 0;
    d->retry_count = 0;
    d->disabled = FALSE;
1304
    d->sleep_before_run = 0;
1305
    d->login = NULL;
1306 1307

    d->timed_login_ok = FALSE;
1308

1309
    d->slave_notify_fd = -1;
1310
    d->master_notify_fd = -1;
1311
    
1312
    return d;
Martin Peterson's avatar
Martin Peterson committed
1313 1314
}

1315 1316 1317 1318
void
gdm_server_whack_clients (GdmDisplay *disp)
{
	int i, screen_count;
1319
	int (* old_xerror_handler) (Display *, XErrorEvent *);
1320 1321