]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - utils/dm-tool.c
99073569057ff5023b458806dcd62387b0dc344c
[sojka/lightdm.git] / utils / 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 ()
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 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                     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 > 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, *sessions;
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         GMainLoop *loop;
394
395         path = g_find_program_in_path ("Xephyr");
396         if (!path)
397         {
398             g_printerr ("Unable to find Xephyr, please install it\n");
399             return EXIT_FAILURE;
400         }
401
402         /* Get a unique display number.  It's racy, but the only reliable method to get one */
403         xephyr_display_number = 0;
404         while (TRUE)
405         {
406             gchar *lock_name;
407             gboolean has_lock;
408
409             lock_name = g_strdup_printf ("/tmp/.X%d-lock", xephyr_display_number);
410             has_lock = g_file_test (lock_name, G_FILE_TEST_EXISTS);
411             g_free (lock_name);
412           
413             if (has_lock)
414                 xephyr_display_number++;
415             else
416                 break;
417         }
418
419         /* Wait for signal from Xephyr is ready */
420         signal (SIGUSR1, xephyr_signal_cb);
421
422         xephyr_command = g_strdup_printf ("Xephyr :%d", xephyr_display_number);
423         if (!g_shell_parse_argv (xephyr_command, NULL, &xephyr_argv, &error) ||
424             !g_spawn_async (NULL, xephyr_argv, NULL,
425                             G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
426                             xephyr_setup_cb, NULL,
427                             &xephyr_pid, &error))
428         {
429             g_printerr ("Error running Xephyr: %s\n", error->message);
430             exit (EXIT_FAILURE);
431         }
432         g_clear_error (&error);
433
434         /* Block until ready */
435         loop = g_main_loop_new (NULL, FALSE);
436         g_main_loop_run (loop);
437     }
438     else if (strcmp (command, "add-local-x-seat") == 0)
439     {
440         GVariant *result;
441         gint display_number;
442         const gchar *path;
443
444         if (n_options != 1)
445         {
446             g_printerr ("Usage add-seat DISPLAY_NUMBER\n");
447             usage ();
448             return EXIT_FAILURE;
449         }
450
451         display_number = atoi (options[0]);
452
453         result = g_dbus_proxy_call_sync (dm_proxy,
454                                          "AddLocalXSeat",
455                                          g_variant_new ("(i)", display_number),
456                                          G_DBUS_CALL_FLAGS_NONE,
457                                          -1,
458                                          NULL,
459                                          &error);
460         if (!result)
461         {
462             g_printerr ("Unable to add local X seat: %s\n", error->message);
463             return EXIT_FAILURE;
464         }
465
466         if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)")))
467         {
468             g_printerr ("Unexpected response to AddLocalXSeat: %s\n", g_variant_get_type_string (result));
469             return EXIT_FAILURE;
470         }
471
472         g_variant_get (result, "(&o)", &path);
473         g_print ("%s\n", path);
474
475         return EXIT_SUCCESS; 
476     }
477     else if (strcmp (command, "add-seat") == 0)
478     {
479         GVariant *result;
480         gchar *type, *path;
481         GVariantBuilder *properties;
482         gint i;
483
484         if (n_options < 1)
485         {
486             g_printerr ("Usage add-seat TYPE [NAME=VALUE...]\n");
487             usage ();
488             return EXIT_FAILURE;
489         }
490
491         type = options[0];
492         properties = g_variant_builder_new (G_VARIANT_TYPE ("a(ss)"));
493       
494         for (i = 1; i < n_options; i++)
495         {
496             gchar *property, *name, *value;
497
498             property = g_strdup (options[i]);
499             name = property;
500             value = strchr (property, '=');
501             if (value)
502             {
503                 *value = '\0';
504                 value++;
505             }
506             else
507                value = "";
508
509             g_variant_builder_add_value (properties, g_variant_new ("(ss)", name, value));
510             g_free (property);
511         }
512       
513         result = g_dbus_proxy_call_sync (dm_proxy,
514                                          "AddSeat",
515                                          g_variant_new ("(sa(ss))", type, properties),
516                                          G_DBUS_CALL_FLAGS_NONE,
517                                          -1,
518                                          NULL,
519                                          &error);
520         g_variant_builder_unref (properties);
521         if (!result)
522         {
523             g_printerr ("Unable to add seat: %s\n", error->message);
524             return EXIT_FAILURE;
525         }
526
527         if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)")))
528         {
529             g_printerr ("Unexpected response to AddSeat: %s\n", g_variant_get_type_string (result));
530             return EXIT_FAILURE;
531         }
532
533         g_variant_get (result, "(&o)", &path);
534         g_print ("%s\n", path);
535
536         return EXIT_SUCCESS;
537     }
538
539     g_printerr ("Unknown command %s\n", command);
540     usage ();
541     return EXIT_FAILURE;
542 }