]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/lightdm.c
move where we insert our own utility PATH
[sojka/lightdm.git] / src / lightdm.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <config.h>
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <sys/stat.h>
17 #include <glib.h>
18 #include <glib/gi18n.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21
22 #include "configuration.h"
23 #include "display-manager.h"
24 #include "xserver.h"
25 #include "user.h"
26 #include "pam-session.h"
27 #include "process.h"
28
29 static gchar *config_path = NULL;
30 static GMainLoop *loop = NULL;
31 static GTimer *log_timer;
32 static FILE *log_file;
33 static gboolean debug = FALSE;
34
35 static DisplayManager *display_manager = NULL;
36
37 static GDBusConnection *bus = NULL;
38 static guint bus_id;
39 static GDBusNodeInfo *seat_info;
40 static GHashTable *seat_bus_entries;
41 static guint seat_index = 0;
42 static GDBusNodeInfo *session_info;
43 static GHashTable *session_bus_entries;
44 static guint session_index = 0;
45
46 typedef struct
47 {
48     gchar *path;
49     gchar *parent_path;
50     gchar *removed_signal;
51     guint bus_id;
52 } BusEntry;
53
54 #define LDM_BUS_NAME "org.freedesktop.DisplayManager"
55
56 static void
57 log_cb (const gchar *log_domain, GLogLevelFlags log_level,
58         const gchar *message, gpointer data)
59 {
60     /* Log everything to a file */
61     if (log_file) {
62         const gchar *prefix;
63
64         switch (log_level & G_LOG_LEVEL_MASK) {
65         case G_LOG_LEVEL_ERROR:
66             prefix = "ERROR:";
67             break;
68         case G_LOG_LEVEL_CRITICAL:
69             prefix = "CRITICAL:";
70             break;
71         case G_LOG_LEVEL_WARNING:
72             prefix = "WARNING:";
73             break;
74         case G_LOG_LEVEL_MESSAGE:
75             prefix = "MESSAGE:";
76             break;
77         case G_LOG_LEVEL_INFO:
78             prefix = "INFO:";
79             break;
80         case G_LOG_LEVEL_DEBUG:
81             prefix = "DEBUG:";
82             break;
83         default:
84             prefix = "LOG:";
85             break;
86         }
87
88         fprintf (log_file, "[%+.2fs] %s %s\n", g_timer_elapsed (log_timer, NULL), prefix, message);
89         fflush (log_file);
90     }
91
92     /* Only show debug if requested */
93     if (log_level & G_LOG_LEVEL_DEBUG) {
94         if (debug)
95             g_log_default_handler (log_domain, log_level, message, data);
96     }
97     else
98         g_log_default_handler (log_domain, log_level, message, data);    
99 }
100
101 static void
102 log_init (void)
103 {
104     gchar *log_dir, *path;
105
106     log_timer = g_timer_new ();
107
108     /* Log to a file */
109     log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
110     path = g_build_filename (log_dir, "lightdm.log", NULL);
111     g_free (log_dir);
112
113     log_file = fopen (path, "w");
114     g_log_set_default_handler (log_cb, NULL);
115
116     g_debug ("Logging to %s", path);
117     g_free (path);
118 }
119
120 static void
121 signal_cb (Process *process, int signum)
122 {
123     g_debug ("Caught %s signal, shutting down", g_strsignal (signum));
124     display_manager_stop (display_manager);
125 }
126
127 static void
128 display_manager_stopped_cb (DisplayManager *display_manager)
129 {
130     g_debug ("Stopping Light Display Manager");
131     exit (EXIT_SUCCESS);
132 }
133
134 static Session *
135 get_session_for_cookie (const gchar *cookie, Seat **seat)
136 {
137     GList *link;
138
139     for (link = display_manager_get_seats (display_manager); link; link = link->next)
140     {
141         Seat *s = link->data;
142         GList *l;
143
144         for (l = seat_get_displays (s); l; l = l->next)
145         {
146             Display *display = l->data;
147             Session *session;
148
149             session = display_get_session (display);
150             if (!session)
151                 continue;
152
153             if (g_strcmp0 (session_get_cookie (session), cookie) == 0)
154             {
155                 if (seat)
156                     *seat = s;
157                 return session;
158             }
159         }
160     }
161
162     return NULL;
163 }
164
165 static GVariant *
166 handle_display_manager_get_property (GDBusConnection       *connection,
167                                      const gchar           *sender,
168                                      const gchar           *object_path,
169                                      const gchar           *interface_name,
170                                      const gchar           *property_name,
171                                      GError               **error,
172                                      gpointer               user_data)
173 {
174     GVariant *result = NULL;
175
176     if (g_strcmp0 (property_name, "Seats") == 0)
177     {
178         GVariantBuilder *builder;
179         GHashTableIter iter;
180         gpointer value;
181
182         builder = g_variant_builder_new (G_VARIANT_TYPE ("ao"));
183         g_hash_table_iter_init (&iter, seat_bus_entries);
184         while (g_hash_table_iter_next (&iter, NULL, &value))
185         {
186             BusEntry *entry = value;
187             g_variant_builder_add_value (builder, g_variant_new_object_path (entry->path));
188         }
189         result = g_variant_builder_end (builder);
190         g_variant_builder_unref (builder);
191     }
192     else if (g_strcmp0 (property_name, "Sessions") == 0)
193     {
194         GVariantBuilder *builder;
195         GHashTableIter iter;
196         gpointer value;
197
198         builder = g_variant_builder_new (G_VARIANT_TYPE ("ao"));
199         g_hash_table_iter_init (&iter, session_bus_entries);
200         while (g_hash_table_iter_next (&iter, NULL, &value))
201         {
202             BusEntry *entry = value;
203             g_variant_builder_add_value (builder, g_variant_new_object_path (entry->path));
204         }
205         result = g_variant_builder_end (builder);
206         g_variant_builder_unref (builder);
207     }
208
209     return result;
210 }
211
212 static void
213 handle_display_manager_call (GDBusConnection       *connection,
214                              const gchar           *sender,
215                              const gchar           *object_path,
216                              const gchar           *interface_name,
217                              const gchar           *method_name,
218                              GVariant              *parameters,
219                              GDBusMethodInvocation *invocation,
220                              gpointer               user_data)
221 {
222     if (g_strcmp0 (method_name, "GetSeatForCookie") == 0)
223     {
224         gchar *cookie;
225         Seat *seat = NULL;
226         BusEntry *entry = NULL;
227
228         if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
229             return;
230
231         g_variant_get (parameters, "(s)", &cookie);
232
233         get_session_for_cookie (cookie, &seat);
234         g_free (cookie);
235
236         if (seat)
237             entry = g_hash_table_lookup (seat_bus_entries, seat);
238         if (entry)
239             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", entry->path));
240         else // FIXME: Need to make proper error
241             g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find seat for cookie");
242     }
243     else if (g_strcmp0 (method_name, "GetSessionForCookie") == 0)
244     {
245         gchar *cookie;
246         Session *session;
247         BusEntry *entry = NULL;
248
249         if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
250             return;
251
252         g_variant_get (parameters, "(s)", &cookie);
253
254         session = get_session_for_cookie (cookie, NULL);
255         g_free (cookie);
256         if (session)
257             entry = g_hash_table_lookup (session_bus_entries, session);
258         if (entry)
259             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", entry->path));
260         else // FIXME: Need to make proper error
261             g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
262     }
263 }
264
265 static GVariant *
266 handle_seat_get_property (GDBusConnection       *connection,
267                           const gchar           *sender,
268                           const gchar           *object_path,
269                           const gchar           *interface_name,
270                           const gchar           *property_name,
271                           GError               **error,
272                           gpointer               user_data)
273 {
274     Seat *seat = user_data;
275     GVariant *result = NULL;
276
277     if (g_strcmp0 (property_name, "CanSwitch") == 0)
278         result = g_variant_new_boolean (seat_get_can_switch (seat));
279     else if (g_strcmp0 (property_name, "Sessions") == 0)
280     {
281         GVariantBuilder *builder;
282         GList *link;
283
284         builder = g_variant_builder_new (G_VARIANT_TYPE ("ao"));
285         for (link = seat_get_displays (seat); link; link = link->next)
286         {
287             Display *display = link->data;
288             BusEntry *entry;
289             entry = g_hash_table_lookup (session_bus_entries, display_get_session (display));
290             if (entry)
291                 g_variant_builder_add_value (builder, g_variant_new_object_path (entry->path));
292         }
293         result = g_variant_builder_end (builder);
294         g_variant_builder_unref (builder);
295     }
296   
297     return result;
298 }
299
300 static void
301 handle_seat_call (GDBusConnection       *connection,
302                   const gchar           *sender,
303                   const gchar           *object_path,
304                   const gchar           *interface_name,
305                   const gchar           *method_name,
306                   GVariant              *parameters,
307                   GDBusMethodInvocation *invocation,
308                   gpointer               user_data)
309 {
310     Seat *seat = user_data;
311   
312     if (g_strcmp0 (method_name, "SwitchToGreeter") == 0)
313     {
314         if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
315             return;
316
317         seat_switch_to_greeter (seat);
318         g_dbus_method_invocation_return_value (invocation, NULL);
319     }
320     else if (g_strcmp0 (method_name, "SwitchToUser") == 0)
321     {
322         const gchar *username, *session_name;
323
324         if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(ss)")))
325             return;
326
327         g_variant_get (parameters, "(&s&s)", &username, &session_name);
328         if (strcmp (session_name, "") == 0)
329             session_name = NULL;
330
331         seat_switch_to_user (seat, username, session_name);
332         g_dbus_method_invocation_return_value (invocation, NULL);
333     }
334     else if (g_strcmp0 (method_name, "SwitchToGuest") == 0)
335     {
336         const gchar *session_name;
337
338         if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
339             return;
340
341         g_variant_get (parameters, "(&s)", &session_name);
342         if (strcmp (session_name, "") == 0)
343             session_name = NULL;
344
345         seat_switch_to_guest (seat, session_name);
346         g_dbus_method_invocation_return_value (invocation, NULL);
347     }
348 }
349
350 static GVariant *
351 handle_session_get_property (GDBusConnection       *connection,
352                              const gchar           *sender,
353                              const gchar           *object_path,
354                              const gchar           *interface_name,
355                              const gchar           *property_name,
356                              GError               **error,
357                              gpointer               user_data)
358 {
359     Session *session = user_data;
360     BusEntry *entry;
361
362     entry = g_hash_table_lookup (session_bus_entries, session);
363     if (g_strcmp0 (property_name, "Seat") == 0)
364         return g_variant_new_object_path (entry ? entry->parent_path : "");
365     else if (g_strcmp0 (property_name, "UserName") == 0)
366         return g_variant_new_string (user_get_name (session_get_user (session)));
367
368     return NULL;
369 }
370
371 static void
372 handle_session_call (GDBusConnection       *connection,
373                      const gchar           *sender,
374                      const gchar           *object_path,
375                      const gchar           *interface_name,
376                      const gchar           *method_name,
377                      GVariant              *parameters,
378                      GDBusMethodInvocation *invocation,
379                      gpointer               user_data)
380 {
381 }
382
383 static BusEntry *
384 bus_entry_new (const gchar *path, const gchar *parent_path, const gchar *removed_signal)
385 {
386     BusEntry *entry;
387
388     entry = g_malloc0 (sizeof (BusEntry));
389     entry->path = g_strdup (path);
390     entry->parent_path = g_strdup (parent_path);
391     entry->removed_signal = g_strdup (removed_signal);
392
393     return entry;
394 }
395
396 static void
397 bus_entry_free (gpointer data)
398 {
399     BusEntry *entry = data;
400     g_dbus_connection_unregister_object (bus, entry->bus_id);
401
402     g_dbus_connection_emit_signal (bus,
403                                    NULL,
404                                    "/org/freedesktop/DisplayManager",
405                                    "org.freedesktop.DisplayManager",
406                                    entry->removed_signal,
407                                    g_variant_new ("(o)", entry->path),
408                                    NULL);
409
410     g_free (entry->path);
411     g_free (entry->parent_path);
412     g_free (entry->removed_signal);
413     g_free (entry);
414 }
415
416 static void
417 session_created_cb (Display *display, Session *session, Seat *seat)
418 {
419     BusEntry *seat_entry;
420     gchar *path;
421
422     seat_entry = g_hash_table_lookup (seat_bus_entries, seat);
423     process_set_env (PROCESS (session), "XDG_SEAT_PATH", seat_entry->path);
424
425     path = g_strdup_printf ("/org/freedesktop/DisplayManager/Session%d", session_index);
426     session_index++;
427     process_set_env (PROCESS (session), "XDG_SESSION_PATH", path);
428     g_free (path);
429 }
430
431 static void
432 session_started_cb (Display *display, Seat *seat)
433 {
434     static const GDBusInterfaceVTable session_vtable =
435     {
436         handle_session_call,
437         handle_session_get_property
438     };
439     Session *session;
440     BusEntry *seat_entry, *entry;
441
442     session = display_get_session (display);
443
444     seat_entry = g_hash_table_lookup (seat_bus_entries, seat);
445     entry = bus_entry_new (process_get_env (PROCESS (session), "XDG_SEAT_PATH"), seat_entry ? seat_entry->path : NULL, "SessionRemoved");
446     g_hash_table_insert (session_bus_entries, g_object_ref (session), entry);
447
448     entry->bus_id = g_dbus_connection_register_object (bus,
449                                                        entry->path,
450                                                        session_info->interfaces[0],
451                                                        &session_vtable,
452                                                        g_object_ref (session), g_object_unref,
453                                                        NULL);
454     g_dbus_connection_emit_signal (bus,
455                                    NULL,
456                                    "/org/freedesktop/DisplayManager",
457                                    "org.freedesktop.DisplayManager",
458                                    "SessionAdded",
459                                    g_variant_new ("(o)", entry->path),
460                                    NULL);
461 }
462
463 static void
464 session_stopped_cb (Display *display)
465 {
466     g_hash_table_remove (session_bus_entries, display_get_session (display));
467 }
468
469 static void
470 display_added_cb (Seat *seat, Display *display)
471 {
472     g_signal_connect (display, "session-created", G_CALLBACK (session_created_cb), seat);  
473     g_signal_connect (display, "session-started", G_CALLBACK (session_started_cb), seat);
474     g_signal_connect (display, "session-stopped", G_CALLBACK (session_stopped_cb), NULL);
475 }
476
477 static void
478 seat_added_cb (DisplayManager *display_manager, Seat *seat)
479 {
480     static const GDBusInterfaceVTable seat_vtable =
481     {
482         handle_seat_call,
483         handle_seat_get_property
484     };
485     GList *link;
486     gchar *path;
487     BusEntry *entry;
488
489     g_signal_connect (seat, "display-added", G_CALLBACK (display_added_cb), NULL);
490     for (link = seat_get_displays (seat); link; link = link->next)
491         display_added_cb (seat, (Display *) link->data);
492
493     path = g_strdup_printf ("/org/freedesktop/DisplayManager/Seat%d", seat_index);
494     seat_index++;
495
496     entry = bus_entry_new (path, NULL, "SeatRemoved");
497     g_free (path);
498     g_hash_table_insert (seat_bus_entries, g_object_ref (seat), entry);
499
500     entry->bus_id = g_dbus_connection_register_object (bus,
501                                                        entry->path,
502                                                        seat_info->interfaces[0],
503                                                        &seat_vtable,
504                                                        g_object_ref (seat), g_object_unref,
505                                                        NULL);
506     g_dbus_connection_emit_signal (bus,
507                                    NULL,
508                                    "/org/freedesktop/DisplayManager",
509                                    "org.freedesktop.DisplayManager",
510                                    "SeatAdded",
511                                    g_variant_new ("(o)", entry->path),
512                                    NULL);
513 }
514
515 static void
516 seat_removed_cb (Seat *seat)
517 {
518     g_hash_table_remove (seat_bus_entries, seat);
519 }
520
521 static void
522 bus_acquired_cb (GDBusConnection *connection,
523                  const gchar     *name,
524                  gpointer         user_data)
525 {
526     const gchar *display_manager_interface =
527         "<node>"
528         "  <interface name='org.freedesktop.DisplayManager'>"
529         "    <property name='Seats' type='ao' access='read'/>"
530         "    <property name='Sessions' type='ao' access='read'/>"
531         "    <method name='GetSeatForCookie'>"
532         "      <arg name='cookie' direction='in' type='s'/>"
533         "      <arg name='seat' direction='out' type='o'/>"
534         "    </method>"
535         "    <method name='GetSessionForCookie'>"
536         "      <arg name='cookie' direction='in' type='s'/>"
537         "      <arg name='session' direction='out' type='o'/>"
538         "    </method>"
539         "    <signal name='SeatAdded'>"
540         "      <arg name='seat' type='o'/>"
541         "    </signal>"
542         "    <signal name='SeatRemoved'>"
543         "      <arg name='seat' type='o'/>"
544         "    </signal>"
545         "    <signal name='SessionAdded'>"
546         "      <arg name='session' type='o'/>"
547         "    </signal>"
548         "    <signal name='SessionRemoved'>"
549         "      <arg name='session' type='o'/>"
550         "    </signal>"
551         "  </interface>"
552         "</node>";
553     static const GDBusInterfaceVTable display_manager_vtable =
554     {
555         handle_display_manager_call,
556         handle_display_manager_get_property
557     };
558     const gchar *seat_interface =
559         "<node>"
560         "  <interface name='org.freedesktop.DisplayManager.Seat'>"
561         "    <property name='CanSwitch' type='b' access='read'/>"
562         "    <property name='Sessions' type='ao' access='read'/>"
563         "    <method name='SwitchToGreeter'/>"
564         "    <method name='SwitchToUser'>"
565         "      <arg name='username' direction='in' type='s'/>"
566         "      <arg name='session-name' direction='in' type='s'/>"
567         "    </method>"
568         "    <method name='SwitchToGuest'>"
569         "      <arg name='session-name' direction='in' type='s'/>"
570         "    </method>"
571         "  </interface>"
572         "</node>";
573     const gchar *session_interface =
574         "<node>"
575         "  <interface name='org.freedesktop.DisplayManager.Session'>"
576         "    <property name='Seat' type='o' access='read'/>"
577         "    <property name='UserName' type='s' access='read'/>"
578         "  </interface>"
579         "</node>";
580     GDBusNodeInfo *display_manager_info;
581     GList *link;
582
583     bus = connection;
584
585     display_manager_info = g_dbus_node_info_new_for_xml (display_manager_interface, NULL);
586     g_assert (display_manager_info != NULL);
587     seat_info = g_dbus_node_info_new_for_xml (seat_interface, NULL);
588     g_assert (seat_info != NULL);
589     session_info = g_dbus_node_info_new_for_xml (session_interface, NULL);
590     g_assert (session_info != NULL);
591
592     bus_id = g_dbus_connection_register_object (connection,
593                                                 "/org/freedesktop/DisplayManager",
594                                                 display_manager_info->interfaces[0],
595                                                 &display_manager_vtable,
596                                                 NULL, NULL,
597                                                 NULL);
598
599     seat_bus_entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, bus_entry_free);
600     session_bus_entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, bus_entry_free);
601
602     g_signal_connect (display_manager, "seat-added", G_CALLBACK (seat_added_cb), NULL);
603     g_signal_connect (display_manager, "seat-removed", G_CALLBACK (seat_removed_cb), NULL);
604     for (link = display_manager_get_seats (display_manager); link; link = link->next)
605         seat_added_cb (display_manager, (Seat *) link->data);
606 }
607
608 static void
609 name_lost_cb (GDBusConnection *connection,
610               const gchar *name,
611               gpointer user_data)
612 {
613     if (connection)
614         g_printerr ("Failed to use bus name " LDM_BUS_NAME ", do you have appropriate permissions?\n");
615     else
616         g_printerr ("Failed to get D-Bus connection\n");
617
618     exit (EXIT_FAILURE);
619 }
620
621 static gchar *
622 path_make_absolute (gchar *path)
623 {
624     gchar *cwd, *abs_path;
625   
626     if (!path)
627         return NULL;
628
629     if (g_path_is_absolute (path))
630         return path;
631
632     cwd = g_get_current_dir ();
633     abs_path = g_build_filename (cwd, path, NULL);
634     g_free (path);
635
636     return abs_path;
637 }
638
639 int
640 main (int argc, char **argv)
641 {
642     FILE *pid_file;
643     GOptionContext *option_context;
644     gboolean explicit_config = FALSE;
645     gboolean test_mode = FALSE;
646     gchar *pid_path = "/var/run/lightdm.pid";
647     gchar *xserver_command = NULL;
648     gchar *passwd_path = NULL;
649     gchar *xsessions_dir = NULL;
650     gchar *xgreeters_dir = NULL;
651     gchar *greeter_session = NULL;
652     gchar *user_session = NULL;
653     gchar *session_wrapper = NULL;
654     gchar *config_dir;
655     gchar *log_dir = NULL;
656     gchar *run_dir = NULL;
657     gchar *cache_dir = NULL;
658     gchar *default_log_dir = g_strdup (LOG_DIR);
659     gchar *default_run_dir = g_strdup (RUN_DIR);
660     gchar *default_cache_dir = g_strdup (CACHE_DIR);
661     gchar *minimum_vt = NULL;
662     gchar *minimum_display_number = NULL;
663     gboolean show_version = FALSE;
664     GOptionEntry options[] = 
665     {
666         { "config", 'c', 0, G_OPTION_ARG_STRING, &config_path,
667           /* Help string for command line --config flag */
668           N_("Use configuration file"), NULL },
669         { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug,
670           /* Help string for command line --debug flag */
671           N_("Print debugging messages"), NULL },
672         { "test-mode", 0, 0, G_OPTION_ARG_NONE, &test_mode,
673           /* Help string for command line --test-mode flag */
674           N_("Run as unprivileged user, skipping things that require root access"), NULL },
675         { "passwd-file", 0, 0, G_OPTION_ARG_STRING, &passwd_path,
676           /* Help string for command line --use-passwd flag */
677           N_("Use the given password file for authentication (for testing, requires --no-root)"), "FILE" },
678         { "pid-file", 0, 0, G_OPTION_ARG_STRING, &pid_path,
679           /* Help string for command line --pid-file flag */
680           N_("File to write PID into"), "FILE" },
681         { "xserver-command", 0, 0, G_OPTION_ARG_STRING, &xserver_command,
682           /* Help string for command line --xserver-command flag */
683           N_("Command to run X servers"), "COMMAND" },
684         { "greeter-session", 0, 0, G_OPTION_ARG_STRING, &greeter_session,
685           /* Help string for command line --greeter-session flag */
686           N_("Greeter session"), "SESSION" },
687         { "user-session", 0, 0, G_OPTION_ARG_STRING, &user_session,
688           /* Help string for command line --user-session flag */
689           N_("User session"), "SESSION" },
690         { "session-wrapper", 0, 0, G_OPTION_ARG_STRING, &session_wrapper,
691           /* Help string for command line --session-wrapper flag */
692           N_("Session wrapper"), "SESSION" },
693         { "minimum-vt", 0, 0, G_OPTION_ARG_STRING, &minimum_vt,
694           /* Help string for command line --minimum-vt flag */
695           N_("Minimum VT to use for X servers"), "NUMBER" },
696         { "minimum-display-number", 0, 0, G_OPTION_ARG_STRING, &minimum_display_number,
697           /* Help string for command line --minimum-display-number flag */
698           N_("Minimum display number to use for X servers"), "NUMBER" },
699         { "xsessions-dir", 0, 0, G_OPTION_ARG_STRING, &xsessions_dir,
700           /* Help string for command line --xsessions-dir flag */
701           N_("Directory to load X sessions from"), "DIRECTORY" },
702         { "xgreeters-dir", 0, 0, G_OPTION_ARG_STRING, &xgreeters_dir,
703           /* Help string for command line --xgreeters-dir flag */
704           N_("Directory to load X greeters from"), "DIRECTORY" },
705         { "log-dir", 0, 0, G_OPTION_ARG_STRING, &log_dir,
706           /* Help string for command line --log-dir flag */
707           N_("Directory to write logs to"), "DIRECTORY" },
708         { "run-dir", 0, 0, G_OPTION_ARG_STRING, &run_dir,
709           /* Help string for command line --run-dir flag */
710           N_("Directory to store running state"), "DIRECTORY" },
711         { "cache-dir", 0, 0, G_OPTION_ARG_STRING, &cache_dir,
712           /* Help string for command line --cache-dir flag */
713           N_("Directory to cached information"), "DIRECTORY" },
714         { "version", 'v', 0, G_OPTION_ARG_NONE, &show_version,
715           /* Help string for command line --version flag */
716           N_("Show release version"), NULL },
717         { NULL }
718     };
719     GError *error = NULL;
720
721     g_thread_init (NULL);
722     g_type_init ();
723
724     g_signal_connect (process_get_current (), "got-signal", G_CALLBACK (signal_cb), NULL);
725
726     option_context = g_option_context_new (/* Arguments and description for --help test */
727                                            _("- Display Manager"));
728     g_option_context_add_main_entries (option_context, options, GETTEXT_PACKAGE);
729     if (!g_option_context_parse (option_context, &argc, &argv, &error))
730     {
731         fprintf (stderr, "%s\n", error->message);
732         fprintf (stderr, /* Text printed out when an unknown command-line argument provided */
733                  _("Run '%s --help' to see a full list of available command line options."), argv[0]);
734         fprintf (stderr, "\n");
735         return EXIT_FAILURE;
736     }
737     g_clear_error (&error);
738
739     if (config_path)
740     {
741         config_dir = g_path_get_basename (config_path);
742         config_dir = path_make_absolute (config_dir);
743         explicit_config = TRUE;
744     }
745     else
746     {
747         config_dir = g_strdup (CONFIG_DIR);
748         config_path = g_build_filename (config_dir, "lightdm.conf", NULL);
749     }
750     config_set_string (config_get_instance (), "LightDM", "config-directory", config_dir);
751     g_free (config_dir);
752
753     if (!test_mode && getuid () != 0)
754     {
755         g_printerr ("Only root can run Light Display Manager.  To run as a regular user for testing run with the --test-mode flag.\n");
756         return EXIT_FAILURE;
757     }
758
759     /* If running inside an X server use Xephyr for display */
760     if (getenv ("DISPLAY") && getuid () != 0)
761     {
762         gchar *xserver_path;
763
764         xserver_path = g_find_program_in_path ("Xephyr");
765         if (!xserver_path)
766         {
767             g_printerr ("Running inside an X server requires Xephyr to be installed but it cannot be found.  Please install it or update your PATH environment variable.\n");
768             return EXIT_FAILURE;
769         }
770         g_free (xserver_path);
771     }
772
773     /* Don't allow to be run as root and use a password file (asking for danger!) */
774     if (getuid () == 0 && passwd_path)
775     {
776         g_printerr ("Only allowed to use --passwd-file when running with --no-root.\n"); 
777         return EXIT_FAILURE;
778     }
779
780     if (show_version)
781     {
782         /* NOTE: Is not translated so can be easily parsed */
783         g_printerr ("lightdm %s\n", VERSION);
784         return EXIT_SUCCESS;
785     }
786
787     /* Write PID file */
788     pid_file = fopen (pid_path, "w");
789     if (pid_file)
790     {
791         fprintf (pid_file, "%d\n", getpid ());
792         fclose (pid_file);
793     }
794
795     /* Always use absolute directories as child processes may run from different locations */
796     xsessions_dir = path_make_absolute (xsessions_dir);
797     xgreeters_dir = path_make_absolute (xgreeters_dir);
798
799     /* If not running as root write output to directories we control */
800     if (getuid () != 0)
801     {
802         g_free (default_log_dir);
803         default_log_dir = g_build_filename (g_get_user_cache_dir (), "lightdm", "log", NULL);
804         g_free (default_run_dir);
805         default_run_dir = g_build_filename (g_get_user_cache_dir (), "lightdm", "run", NULL);
806         g_free (default_cache_dir);
807         default_cache_dir = g_build_filename (g_get_user_cache_dir (), "lightdm", "cache", NULL);
808     }
809
810     /* Load config file */
811     if (!config_load_from_file (config_get_instance (), config_path, &error))
812     {
813         if (explicit_config || !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
814         {
815             g_printerr ("Failed to load configuration from %s: %s\n", config_path, error->message);
816             exit (EXIT_FAILURE);
817         }
818     }
819     g_clear_error (&error);
820
821     /* Set default values */
822     if (!config_has_key (config_get_instance (), "LightDM", "start-default-seat"))
823         config_set_boolean (config_get_instance (), "LightDM", "start-default-seat", TRUE);
824     if (!config_has_key (config_get_instance (), "LightDM", "minimum-vt"))
825         config_set_integer (config_get_instance (), "LightDM", "minimum-vt", 7);
826     if (!config_has_key (config_get_instance (), "LightDM", "guest-account-script"))
827         config_set_string (config_get_instance (), "LightDM", "guest-account-script", "guest-account");
828     if (!config_has_key (config_get_instance (), "LightDM", "greeter-user"))
829         config_set_string (config_get_instance (), "LightDM", "greeter-user", GREETER_USER);
830     if (!config_has_key (config_get_instance (), "SeatDefaults", "type"))
831         config_set_string (config_get_instance (), "SeatDefaults", "type", "xlocal");
832     if (!config_has_key (config_get_instance (), "SeatDefaults", "xserver-command"))
833         config_set_string (config_get_instance (), "SeatDefaults", "xserver-command", "X");
834     if (!config_has_key (config_get_instance (), "SeatDefaults", "xsessions-directory"))
835         config_set_string (config_get_instance (), "SeatDefaults", "xsessions-directory", XSESSIONS_DIR);
836     if (!config_has_key (config_get_instance (), "SeatDefaults", "xgreeters-directory"))
837         config_set_string (config_get_instance (), "SeatDefaults", "xgreeters-directory", XGREETERS_DIR);
838     if (!config_has_key (config_get_instance (), "SeatDefaults", "allow-guest"))
839         config_set_boolean (config_get_instance (), "SeatDefaults", "allow-guest", TRUE);
840     if (!config_has_key (config_get_instance (), "SeatDefaults", "greeter-session"))
841         config_set_string (config_get_instance (), "SeatDefaults", "greeter-session", GREETER_SESSION);
842     if (!config_has_key (config_get_instance (), "SeatDefaults", "user-session"))
843         config_set_string (config_get_instance (), "SeatDefaults", "user-session", USER_SESSION);
844     if (!config_has_key (config_get_instance (), "SeatDefaults", "session-wrapper"))
845         config_set_string (config_get_instance (), "SeatDefaults", "session-wrapper", "lightdm-session");
846     if (!config_has_key (config_get_instance (), "LightDM", "log-directory"))
847         config_set_string (config_get_instance (), "LightDM", "log-directory", default_log_dir);
848     g_free (default_log_dir);
849     if (!config_has_key (config_get_instance (), "LightDM", "run-directory"))
850         config_set_string (config_get_instance (), "LightDM", "run-directory", default_run_dir);
851     g_free (default_run_dir);
852     if (!config_has_key (config_get_instance (), "LightDM", "cache-directory"))
853         config_set_string (config_get_instance (), "LightDM", "cache-directory", default_cache_dir);
854     g_free (default_cache_dir);
855
856     /* Override defaults */
857     if (minimum_vt)
858         config_set_integer (config_get_instance (), "LightDM", "minimum-vt", atoi (minimum_vt));
859     g_free (minimum_vt);
860     if (minimum_display_number)
861         config_set_integer (config_get_instance (), "LightDM", "minimum-display-number", atoi (minimum_display_number));
862     g_free (minimum_display_number);
863     if (log_dir)
864         config_set_string (config_get_instance (), "LightDM", "log-directory", log_dir);
865     g_free (log_dir);
866     if (run_dir)
867         config_set_string (config_get_instance (), "LightDM", "run-directory", run_dir);
868     g_free (run_dir);
869     if (cache_dir)
870         config_set_string (config_get_instance (), "LightDM", "cache-directory", cache_dir);
871     g_free (cache_dir);
872     if (xserver_command)
873         config_set_string (config_get_instance (), "SeatDefaults", "xserver-command", xserver_command);
874     g_free (xserver_command);
875     if (greeter_session)
876         config_set_string (config_get_instance (), "SeatDefaults", "greeter-session", greeter_session);
877     g_free (greeter_session);
878     if (user_session)
879         config_set_string (config_get_instance (), "SeatDefaults", "user-session", user_session);
880     g_free (user_session);
881     if (session_wrapper)
882         config_set_string (config_get_instance (), "SeatDefaults", "session-wrapper", session_wrapper);
883     g_free (session_wrapper);
884     if (xsessions_dir)
885         config_set_string (config_get_instance (), "SeatDefaults", "xsessions-directory", xsessions_dir);
886     g_free (xsessions_dir);
887     if (xgreeters_dir)
888         config_set_string (config_get_instance (), "SeatDefaults", "xgreeters-directory", xgreeters_dir);
889     g_free (xgreeters_dir);
890
891     /* Create run and cache directories */
892     g_mkdir_with_parents (config_get_string (config_get_instance (), "LightDM", "log-directory"), S_IRWXU | S_IXGRP | S_IXOTH);  
893     g_mkdir_with_parents (config_get_string (config_get_instance (), "LightDM", "run-directory"), S_IRWXU | S_IXGRP | S_IXOTH);
894     g_mkdir_with_parents (config_get_string (config_get_instance (), "LightDM", "cache-directory"), S_IRWXU | S_IXGRP | S_IXOTH);
895
896     loop = g_main_loop_new (NULL, FALSE);
897
898     log_init ();
899
900     g_debug ("Starting Light Display Manager %s, UID=%i PID=%i", VERSION, getuid (), getpid ());
901
902     g_debug ("Loaded configuration from %s", config_path);
903     g_free (config_path);
904
905     g_bus_own_name (getuid () == 0 ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
906                     LDM_BUS_NAME,
907                     G_BUS_NAME_OWNER_FLAGS_NONE,
908                     bus_acquired_cb,
909                     NULL,
910                     name_lost_cb,
911                     NULL,
912                     NULL);
913
914     if (getuid () != 0)
915         g_debug ("Running in user mode");
916     if (passwd_path)
917     {
918         g_debug ("Using password file '%s' for authentication", passwd_path);
919         user_set_use_passwd_file (passwd_path);
920         pam_session_set_use_passwd_file (passwd_path);
921     }
922     if (getenv ("DISPLAY"))
923         g_debug ("Using Xephyr for X servers");
924
925     display_manager = display_manager_new ();
926     g_signal_connect (display_manager, "stopped", G_CALLBACK (display_manager_stopped_cb), NULL);
927
928     display_manager_start (display_manager);
929
930     g_main_loop_run (loop);
931
932     return EXIT_SUCCESS;
933 }