]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/dm-tool.c
Change log backup to enabled by default - this is probably more useful. We explicitly...
[sojka/lightdm.git] / src / dm-tool.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 <glib.h>
16 #include <glib/gi18n.h>
17 #include <gio/gio.h>
18
19 static GBusType bus_type = G_BUS_TYPE_SYSTEM;
20 static GDBusProxy *dm_proxy, *seat_proxy = NULL;
21
22 static gint xephyr_display_number;
23 static GPid xephyr_pid;
24
25 static void
26 usage (void)
27 {
28     g_printerr (/* Text printed out when an unknown command-line argument provided */
29                 _("Run 'dm-tool --help' to see a full list of available command line options."));
30     g_printerr ("\n");
31 }
32
33 static void
34 xephyr_setup_cb (gpointer user_data)
35 {
36     signal (SIGUSR1, SIG_IGN);
37 }
38
39 static void
40 xephyr_signal_cb (int signum)
41 {
42     gchar *path;
43     GVariant *result;
44     GError *error = NULL;
45
46     result = g_dbus_proxy_call_sync (dm_proxy,
47                                      "AddLocalXSeat",
48                                      g_variant_new ("(i)", xephyr_display_number),
49                                      G_DBUS_CALL_FLAGS_NONE,
50                                      -1,
51                                      NULL,
52                                      &error);
53     if (!result)
54     {
55         g_printerr ("Unable to add seat: %s\n", error->message);
56         kill (xephyr_pid, SIGQUIT);
57         exit (EXIT_FAILURE);
58     }
59
60     if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)")))
61     {
62         g_printerr ("Unexpected response to AddSeat: %s\n", g_variant_get_type_string (result));
63         exit (EXIT_FAILURE);
64     }
65
66     g_variant_get (result, "(&o)", &path);
67     g_print ("%s\n", path);
68
69     exit (EXIT_SUCCESS);
70 }
71
72 static GDBusProxy *
73 get_seat_proxy (void)
74 {
75     GError *error = NULL;
76
77     if (seat_proxy)
78         return seat_proxy;
79
80     if (!g_getenv ("XDG_SEAT_PATH"))
81     {
82         g_printerr ("Not running inside a display manager, XDG_SEAT_PATH not defined\n");
83         exit (EXIT_FAILURE);
84     }
85
86     seat_proxy = g_dbus_proxy_new_for_bus_sync (bus_type,
87                                                 G_DBUS_PROXY_FLAGS_NONE,
88                                                 NULL,
89                                                 "org.freedesktop.DisplayManager",
90                                                 g_getenv ("XDG_SEAT_PATH"),
91                                                 "org.freedesktop.DisplayManager.Seat",
92                                                 NULL,
93                                                 &error);
94     if (!seat_proxy)
95     {
96         g_printerr ("Unable to contact display manager: %s\n", error->message);
97         exit (EXIT_FAILURE);
98     }
99     g_clear_error (&error);
100
101     return seat_proxy;
102 }
103
104 int
105 main (int argc, char **argv)
106 {
107     gchar *command;
108     gint n_options;
109     gchar **options;
110     GError *error = NULL;
111     gint arg_index;
112
113 #if !defined(GLIB_VERSION_2_36)
114     g_type_init ();
115 #endif
116
117     for (arg_index = 1; arg_index < argc; arg_index++)
118     {
119         gchar *arg = argv[arg_index];
120
121         if (!g_str_has_prefix (arg, "-"))
122             break;
123
124         if (strcmp (arg, "-h") == 0 || strcmp (arg, "--help") == 0)
125         {
126             g_printerr ("Usage:\n"
127                         "  dm-tool [OPTION...] COMMAND [ARGS...] - Display Manager tool\n"
128                         "\n"
129                         "Options:\n"
130                         "  -h, --help        Show help options\n"
131                         "  -v, --version     Show release version\n"
132                         "  --session-bus     Use session D-Bus\n"
133                         "\n"
134                         "Commands:\n"
135                         "  switch-to-greeter                                    Switch to the greeter\n"
136                         "  switch-to-user USERNAME [SESSION]                    Switch to a user session\n"
137                         "  switch-to-guest [SESSION]                            Switch to a guest session\n"
138                         "  lock                                                 Lock the current seat\n"
139                         "  list-seats                                           List the active seats\n"
140                         "  add-nested-seat [--fullscreen|--screen DIMENSIONS]   Start a nested display\n"
141                         "  add-local-x-seat DISPLAY_NUMBER                      Add a local X seat\n"
142                         "  add-seat TYPE [NAME=VALUE...]                        Add a dynamic seat\n");
143             return EXIT_SUCCESS;
144         }
145         else if (strcmp (arg, "-v") == 0 || strcmp (arg, "--version") == 0)
146         {
147             /* NOTE: Is not translated so can be easily parsed */
148             g_printerr ("lightdm %s\n", VERSION);
149             return EXIT_SUCCESS;
150         }
151         else if (strcmp (arg, "--session-bus") == 0)
152             bus_type = G_BUS_TYPE_SESSION;
153         else
154         {
155             g_printerr ("Unknown option %s\n", arg);
156             usage ();
157             return EXIT_FAILURE;
158         }
159     }
160
161     if (arg_index >= argc)
162     {
163         g_printerr ("Missing command\n");
164         usage ();
165         return EXIT_FAILURE;
166     }
167
168     dm_proxy = g_dbus_proxy_new_for_bus_sync (bus_type,
169                                               G_DBUS_PROXY_FLAGS_NONE,
170                                               NULL,
171                                               "org.freedesktop.DisplayManager",
172                                               "/org/freedesktop/DisplayManager",
173                                               "org.freedesktop.DisplayManager",
174                                               NULL,
175                                               &error);
176     if (!dm_proxy)
177     {
178         g_printerr ("Unable to contact display manager: %s\n", error->message);
179         return EXIT_FAILURE;
180     }
181     g_clear_error (&error);
182
183     command = argv[arg_index];
184     arg_index++;
185     n_options = argc - arg_index;
186     options = argv + arg_index;
187     if (strcmp (command, "switch-to-greeter") == 0)
188     {
189         if (n_options != 0)
190         {
191             g_printerr ("Usage switch-to-greeter\n");
192             usage ();
193             return EXIT_FAILURE;
194         }
195
196         if (!g_dbus_proxy_call_sync (get_seat_proxy (),
197                                      "SwitchToGreeter",
198                                      g_variant_new ("()"),
199                                      G_DBUS_CALL_FLAGS_NONE,
200                                      -1,
201                                      NULL,
202                                      &error))
203         {
204             g_printerr ("Unable to switch to greeter: %s\n", error->message);
205             return EXIT_FAILURE;
206         }
207         return EXIT_SUCCESS;
208     }
209     else if (strcmp (command, "switch-to-user") == 0)
210     {
211         gchar *username, *session = "";
212
213         if (n_options < 1 || n_options > 2)
214         {
215             g_printerr ("Usage switch-to-user USERNAME [SESSION]\n");
216             usage ();
217             return EXIT_FAILURE;
218         }
219
220         username = options[0];
221         if (n_options == 2)
222             session = options[1];
223
224         if (!g_dbus_proxy_call_sync (get_seat_proxy (),
225                                      "SwitchToUser",
226                                      g_variant_new ("(ss)", username, session),
227                                      G_DBUS_CALL_FLAGS_NONE,
228                                      -1,
229                                      NULL,
230                                      &error))
231         {
232             g_printerr ("Unable to switch to user %s: %s\n", username, error->message);
233             return EXIT_FAILURE;
234         }
235         return EXIT_SUCCESS;
236     }
237     else if (strcmp (command, "switch-to-guest") == 0)
238     {
239         gchar *session = "";
240
241         if (n_options > 1)
242         {
243             g_printerr ("Usage switch-to-guest [SESSION]\n");
244             usage ();
245             return EXIT_FAILURE;
246         }
247
248         if (n_options == 1)
249             session = options[0];
250
251         if (!g_dbus_proxy_call_sync (get_seat_proxy (),
252                                      "SwitchToGuest",
253                                      g_variant_new ("(s)", session),
254                                      G_DBUS_CALL_FLAGS_NONE,
255                                      -1,
256                                      NULL,
257                                      &error))
258         {
259             g_printerr ("Unable to switch to guest: %s\n", error->message);
260             return EXIT_FAILURE;
261         }
262         return EXIT_SUCCESS;
263     }
264     else if (strcmp (command, "lock") == 0)
265     {
266         if (n_options != 0)
267         {
268             g_printerr ("Usage lock\n");
269             usage ();
270             return EXIT_FAILURE;
271         }
272
273         if (!g_dbus_proxy_call_sync (get_seat_proxy (),
274                                      "Lock",
275                                      g_variant_new ("()"),
276                                      G_DBUS_CALL_FLAGS_NONE,
277                                      -1,
278                                      NULL,
279                                      &error))
280         {
281             g_printerr ("Unable to lock seat: %s\n", error->message);
282             return EXIT_FAILURE;
283         }
284         return EXIT_SUCCESS;
285     }
286     else if (strcmp (command, "list-seats") == 0)
287     {
288         GVariant *seats;
289         GVariantIter *seat_iter;
290         gchar *seat_path;
291
292         if (!g_dbus_proxy_get_name_owner (dm_proxy))
293         {
294             g_printerr ("Unable to contact display manager\n");
295             return EXIT_FAILURE;
296         }
297         seats = g_dbus_proxy_get_cached_property (dm_proxy, "Seats");
298
299         g_variant_get (seats, "ao", &seat_iter);
300         while (g_variant_iter_loop (seat_iter, "&o", &seat_path))
301         {
302             gchar *seat_name;
303             GDBusProxy *proxy;
304             gchar **property_names;
305             GVariant *sessions;
306             GVariantIter *session_iter;
307             gchar *session_path;
308             gint i;
309
310             if (g_str_has_prefix (seat_path, "/org/freedesktop/DisplayManager/"))
311                 seat_name = seat_path + strlen ("/org/freedesktop/DisplayManager/");
312             else
313                 seat_name = seat_path;
314
315             proxy = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (dm_proxy),
316                                            G_DBUS_PROXY_FLAGS_NONE,
317                                            NULL,
318                                            "org.freedesktop.DisplayManager",
319                                            seat_path,
320                                            "org.freedesktop.DisplayManager.Seat",
321                                            NULL,
322                                            NULL);
323             if (!proxy || !g_dbus_proxy_get_name_owner (proxy))
324                 continue;
325
326             g_print ("%s\n", seat_name);
327             property_names = g_dbus_proxy_get_cached_property_names (proxy);
328             for (i = 0; property_names[i]; i++)
329             {
330                 GVariant *value;
331
332                 if (strcmp (property_names[i], "Sessions") == 0)
333                     continue;
334
335                 value = g_dbus_proxy_get_cached_property (proxy, property_names[i]);
336                 g_print ("  %s=%s\n", property_names[i], g_variant_print (value, FALSE));
337                 g_variant_unref (value);
338             }
339
340             sessions = g_dbus_proxy_get_cached_property (proxy, "Sessions");
341             if (!sessions)
342                 continue;
343
344             g_variant_get (sessions, "ao", &session_iter);
345             while (g_variant_iter_loop (session_iter, "&o", &session_path))
346             {
347                 GDBusProxy *session_proxy;
348                 gchar *session_name;
349
350                 if (g_str_has_prefix (session_path, "/org/freedesktop/DisplayManager/"))
351                     session_name = session_path + strlen ("/org/freedesktop/DisplayManager/");
352                 else
353                     session_name = session_path;
354
355                 session_proxy = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (dm_proxy),
356                                                        G_DBUS_PROXY_FLAGS_NONE,
357                                                        NULL,
358                                                        "org.freedesktop.DisplayManager",
359                                                        session_path,
360                                                        "org.freedesktop.DisplayManager.Session",
361                                                        NULL,
362                                                        NULL);
363                 if (!session_proxy || !g_dbus_proxy_get_name_owner (session_proxy))
364                     continue;
365
366                 g_print ("  %s\n", session_name);
367                 property_names = g_dbus_proxy_get_cached_property_names (session_proxy);
368                 for (i = 0; property_names[i]; i++)
369                 {
370                     GVariant *value;
371
372                     if (strcmp (property_names[i], "Seat") == 0)
373                         continue;
374
375                     value = g_dbus_proxy_get_cached_property (session_proxy, property_names[i]);
376                     g_print ("    %s=%s\n", property_names[i], g_variant_print (value, FALSE));
377                     g_variant_unref (value);
378                 }
379
380                 g_object_unref (session_proxy);
381             }
382             g_variant_iter_free (session_iter);
383
384             g_object_unref (proxy);
385         }
386         g_variant_iter_free (seat_iter);
387
388         return EXIT_SUCCESS;
389     }
390     else if (strcmp (command, "add-nested-seat") == 0)
391     {
392         gchar *path, *xephyr_command, **xephyr_argv;
393         gchar *dimensions = NULL;
394         GMainLoop *loop;
395
396         path = g_find_program_in_path ("Xephyr");
397         if (!path)
398         {
399             g_printerr ("Unable to find Xephyr, please install it\n");
400             return EXIT_FAILURE;
401         }
402
403         if (n_options > 0)
404         {
405             /* Parse the given options */
406             if (strcmp (options[0], "--fullscreen") == 0 && n_options == 1)
407             {
408                 dimensions = "fullscreen";
409             }
410             else if (strcmp (options[0], "--screen") == 0 && n_options == 2)
411             {
412                 dimensions = options[1];
413             }
414             else
415             {
416                 g_printerr ("Usage add-nested-seat [--fullscreen|--screen DIMENSIONS]\n");
417                 usage ();
418                 return EXIT_FAILURE;
419             }
420         }
421
422         /* Get a unique display number.  It's racy, but the only reliable method to get one */
423         xephyr_display_number = 0;
424         while (TRUE)
425         {
426             gchar *lock_name;
427             gboolean has_lock;
428
429             lock_name = g_strdup_printf ("/tmp/.X%d-lock", xephyr_display_number);
430             has_lock = g_file_test (lock_name, G_FILE_TEST_EXISTS);
431             g_free (lock_name);
432
433             if (has_lock)
434                 xephyr_display_number++;
435             else
436                 break;
437         }
438
439         /* Wait for signal from Xephyr is ready */
440         signal (SIGUSR1, xephyr_signal_cb);
441
442         if (dimensions == NULL)
443         {
444             xephyr_command = g_strdup_printf ("Xephyr :%d ", xephyr_display_number);
445         }
446         else if (strcmp (dimensions, "fullscreen") == 0)
447         {
448             xephyr_command = g_strdup_printf ("Xephyr :%d -fullscreen", xephyr_display_number);
449         }
450         else
451         {
452             xephyr_command = g_strdup_printf ("Xephyr :%d -screen %s", xephyr_display_number, dimensions);
453         }
454         if (!g_shell_parse_argv (xephyr_command, NULL, &xephyr_argv, &error) ||
455             !g_spawn_async (NULL, xephyr_argv, NULL,
456                             G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
457                             xephyr_setup_cb, NULL,
458                             &xephyr_pid, &error))
459         {
460             g_printerr ("Error running Xephyr: %s\n", error->message);
461             exit (EXIT_FAILURE);
462         }
463         g_clear_error (&error);
464
465         /* Block until ready */
466         loop = g_main_loop_new (NULL, FALSE);
467         g_main_loop_run (loop);
468     }
469     else if (strcmp (command, "add-local-x-seat") == 0)
470     {
471         GVariant *result;
472         gint display_number;
473         const gchar *path;
474
475         if (n_options != 1)
476         {
477             g_printerr ("Usage add-seat DISPLAY_NUMBER\n");
478             usage ();
479             return EXIT_FAILURE;
480         }
481
482         display_number = atoi (options[0]);
483
484         result = g_dbus_proxy_call_sync (dm_proxy,
485                                          "AddLocalXSeat",
486                                          g_variant_new ("(i)", display_number),
487                                          G_DBUS_CALL_FLAGS_NONE,
488                                          -1,
489                                          NULL,
490                                          &error);
491         if (!result)
492         {
493             g_printerr ("Unable to add local X seat: %s\n", error->message);
494             return EXIT_FAILURE;
495         }
496
497         if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)")))
498         {
499             g_printerr ("Unexpected response to AddLocalXSeat: %s\n", g_variant_get_type_string (result));
500             return EXIT_FAILURE;
501         }
502
503         g_variant_get (result, "(&o)", &path);
504         g_print ("%s\n", path);
505
506         return EXIT_SUCCESS;
507     }
508     else if (strcmp (command, "add-seat") == 0)
509     {
510         GVariant *result;
511         gchar *type, *path;
512         GVariantBuilder *properties;
513         gint i;
514
515         if (n_options < 1)
516         {
517             g_printerr ("Usage add-seat TYPE [NAME=VALUE...]\n");
518             usage ();
519             return EXIT_FAILURE;
520         }
521
522         type = options[0];
523         properties = g_variant_builder_new (G_VARIANT_TYPE ("a(ss)"));
524
525         for (i = 1; i < n_options; i++)
526         {
527             gchar *property, *name, *value;
528
529             property = g_strdup (options[i]);
530             name = property;
531             value = strchr (property, '=');
532             if (value)
533             {
534                 *value = '\0';
535                 value++;
536             }
537             else
538                value = "";
539
540             g_variant_builder_add_value (properties, g_variant_new ("(ss)", name, value));
541             g_free (property);
542         }
543
544         result = g_dbus_proxy_call_sync (dm_proxy,
545                                          "AddSeat",
546                                          g_variant_new ("(sa(ss))", type, properties),
547                                          G_DBUS_CALL_FLAGS_NONE,
548                                          -1,
549                                          NULL,
550                                          &error);
551         g_variant_builder_unref (properties);
552         if (!result)
553         {
554             g_printerr ("Unable to add seat: %s\n", error->message);
555             return EXIT_FAILURE;
556         }
557
558         if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)")))
559         {
560             g_printerr ("Unexpected response to AddSeat: %s\n", g_variant_get_type_string (result));
561             return EXIT_FAILURE;
562         }
563
564         g_variant_get (result, "(&o)", &path);
565         g_print ("%s\n", path);
566
567         return EXIT_SUCCESS;
568     }
569
570     g_printerr ("Unknown command %s\n", command);
571     usage ();
572     return EXIT_FAILURE;
573 }