]> Pileus Git - ~andy/gtk/blob - gtk/gtkmountoperation-x11.c
Bug 587485 – GMountOperation::show-processes support
[~andy/gtk] / gtk / gtkmountoperation-x11.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* GTK - The GIMP Toolkit
3  * Copyright (C) David Zeuthen <davidz@redhat.com>
4  * Copyright (C) 2001 Havoc Pennington
5  * Copyright (C) 2005-2007 Vincent Untz
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 #include "config.h"
31
32 #include <string.h>
33 #include <stdlib.h>
34 #include <gio/gio.h>
35 #include "x11/gdkx.h"
36 #include <X11/Xatom.h>
37 #include <gtk/gtkicontheme.h>
38 #include "gtkintl.h"
39
40 /* for the kill(2) system call and errno - POSIX.1-2001 and later */
41 #include <sys/types.h>
42 #include <signal.h>
43 #include <errno.h>
44
45 #include "gtkmountoperationprivate.h"
46
47
48 /* ---------------------------------------------------------------------------------------------------- */
49 /* these functions are based on code from libwnck (LGPLv2) */
50
51 static gboolean get_window_list   (Display   *xdisplay,
52                                    Window     xwindow,
53                                    Atom       atom,
54                                    Window   **windows,
55                                    int       *len);
56
57 static char*    get_utf8_property (Display   *xdisplay,
58                                    Window     xwindow,
59                                    Atom       atom);
60
61 static gboolean get_cardinal      (Display   *xdisplay,
62                                    Window     xwindow,
63                                    Atom       atom,
64                                    int       *val);
65
66 static gboolean read_rgb_icon     (Display   *xdisplay,
67                                    Window     xwindow,
68                                    int        ideal_width,
69                                    int        ideal_height,
70                                    int       *width,
71                                    int       *height,
72                                    guchar   **pixdata);
73
74
75 static gboolean
76 get_cardinal (Display *xdisplay,
77               Window   xwindow,
78               Atom     atom,
79               int     *val)
80 {
81   Atom type;
82   int format;
83   gulong nitems;
84   gulong bytes_after;
85   gulong *num;
86   int err, result;
87
88   *val = 0;
89
90   gdk_error_trap_push ();
91   type = None;
92   result = XGetWindowProperty (xdisplay,
93                                xwindow,
94                                atom,
95                                0, G_MAXLONG,
96                                False, XA_CARDINAL, &type, &format, &nitems,
97                                &bytes_after, (void*)&num);
98   XSync (xdisplay, False);
99   err = gdk_error_trap_pop ();
100
101   if (err != Success ||
102       result != Success)
103     return FALSE;
104
105   if (type != XA_CARDINAL)
106     {
107       XFree (num);
108       return FALSE;
109     }
110
111   *val = *num;
112
113   XFree (num);
114
115   return TRUE;
116 }
117
118 static char*
119 get_utf8_property (Display *xdisplay,
120                    Window   xwindow,
121                    Atom     atom)
122 {
123   Atom type;
124   int format;
125   gulong nitems;
126   gulong bytes_after;
127   gchar *val;
128   int err, result;
129   char *retval;
130   Atom utf8_string;
131
132   utf8_string = gdk_x11_get_xatom_by_name ("UTF8_STRING");
133
134   gdk_error_trap_push ();
135   type = None;
136   val = NULL;
137   result = XGetWindowProperty (xdisplay,
138                                xwindow,
139                                atom,
140                                0, G_MAXLONG,
141                                False, utf8_string,
142                                &type, &format, &nitems,
143                                &bytes_after, (guchar **)&val);
144   XSync (xdisplay, False);
145   err = gdk_error_trap_pop ();
146
147   if (err != Success ||
148       result != Success)
149     return NULL;
150
151   if (type != utf8_string ||
152       format != 8 ||
153       nitems == 0)
154     {
155       if (val)
156         XFree (val);
157       return NULL;
158     }
159
160   if (!g_utf8_validate (val, nitems, NULL))
161     {
162       g_warning ("Property %s contained invalid UTF-8\n",
163                  gdk_x11_get_xatom_name (atom));
164       XFree (val);
165       return NULL;
166     }
167
168   retval = g_strndup (val, nitems);
169
170   XFree (val);
171
172   return retval;
173 }
174
175 static gboolean
176 find_largest_sizes (gulong *data,
177                     gulong  nitems,
178                     int    *width,
179                     int    *height)
180 {
181   *width = 0;
182   *height = 0;
183
184   while (nitems > 0)
185     {
186       int w, h;
187       gboolean replace;
188
189       replace = FALSE;
190
191       if (nitems < 3)
192         return FALSE; /* no space for w, h */
193
194       w = data[0];
195       h = data[1];
196
197       if (nitems < ((w * h) + 2))
198         return FALSE; /* not enough data */
199
200       *width = MAX (w, *width);
201       *height = MAX (h, *height);
202
203       data += (w * h) + 2;
204       nitems -= (w * h) + 2;
205     }
206
207   return TRUE;
208 }
209
210 static gboolean
211 find_best_size (gulong  *data,
212                 gulong   nitems,
213                 int      ideal_width,
214                 int      ideal_height,
215                 int     *width,
216                 int     *height,
217                 gulong **start)
218 {
219   int best_w;
220   int best_h;
221   gulong *best_start;
222   int max_width, max_height;
223
224   *width = 0;
225   *height = 0;
226   *start = NULL;
227
228   if (!find_largest_sizes (data, nitems, &max_width, &max_height))
229     return FALSE;
230
231   if (ideal_width < 0)
232     ideal_width = max_width;
233   if (ideal_height < 0)
234     ideal_height = max_height;
235
236   best_w = 0;
237   best_h = 0;
238   best_start = NULL;
239
240   while (nitems > 0)
241     {
242       int w, h;
243       gboolean replace;
244
245       replace = FALSE;
246
247       if (nitems < 3)
248         return FALSE; /* no space for w, h */
249
250       w = data[0];
251       h = data[1];
252
253       if (nitems < ((w * h) + 2))
254         break; /* not enough data */
255
256       if (best_start == NULL)
257         {
258           replace = TRUE;
259         }
260       else
261         {
262           /* work with averages */
263           const int ideal_size = (ideal_width + ideal_height) / 2;
264           int best_size = (best_w + best_h) / 2;
265           int this_size = (w + h) / 2;
266
267           /* larger than desired is always better than smaller */
268           if (best_size < ideal_size &&
269               this_size >= ideal_size)
270             replace = TRUE;
271           /* if we have too small, pick anything bigger */
272           else if (best_size < ideal_size &&
273                    this_size > best_size)
274             replace = TRUE;
275           /* if we have too large, pick anything smaller
276            * but still >= the ideal
277            */
278           else if (best_size > ideal_size &&
279                    this_size >= ideal_size &&
280                    this_size < best_size)
281             replace = TRUE;
282         }
283
284       if (replace)
285         {
286           best_start = data + 2;
287           best_w = w;
288           best_h = h;
289         }
290
291       data += (w * h) + 2;
292       nitems -= (w * h) + 2;
293     }
294
295   if (best_start)
296     {
297       *start = best_start;
298       *width = best_w;
299       *height = best_h;
300       return TRUE;
301     }
302   else
303     return FALSE;
304 }
305
306 static void
307 argbdata_to_pixdata (gulong  *argb_data,
308                      int      len,
309                      guchar **pixdata)
310 {
311   guchar *p;
312   int i;
313
314   *pixdata = g_new (guchar, len * 4);
315   p = *pixdata;
316
317   /* One could speed this up a lot. */
318   i = 0;
319   while (i < len)
320     {
321       guint argb;
322       guint rgba;
323
324       argb = argb_data[i];
325       rgba = (argb << 8) | (argb >> 24);
326
327       *p = rgba >> 24;
328       ++p;
329       *p = (rgba >> 16) & 0xff;
330       ++p;
331       *p = (rgba >> 8) & 0xff;
332       ++p;
333       *p = rgba & 0xff;
334       ++p;
335
336       ++i;
337     }
338 }
339
340 static gboolean
341 read_rgb_icon (Display   *xdisplay,
342                Window     xwindow,
343                int        ideal_width,
344                int        ideal_height,
345                int       *width,
346                int       *height,
347                guchar   **pixdata)
348 {
349   Atom type;
350   int format;
351   gulong nitems;
352   gulong bytes_after;
353   int result, err;
354   gulong *data;
355   gulong *best;
356   int w, h;
357
358   gdk_error_trap_push ();
359   type = None;
360   data = NULL;
361   result = XGetWindowProperty (xdisplay,
362                                xwindow,
363                                gdk_x11_get_xatom_by_name ("_NET_WM_ICON"),
364                                0, G_MAXLONG,
365                                False, XA_CARDINAL, &type, &format, &nitems,
366                                &bytes_after, (void*)&data);
367
368   XSync (xdisplay, False);
369   err = gdk_error_trap_pop ();
370
371   if (err != Success ||
372       result != Success)
373     return FALSE;
374
375   if (type != XA_CARDINAL)
376     {
377       XFree (data);
378       return FALSE;
379     }
380
381   if (!find_best_size (data, nitems,
382                        ideal_width, ideal_height,
383                        &w, &h, &best))
384     {
385       XFree (data);
386       return FALSE;
387     }
388
389   *width = w;
390   *height = h;
391
392   argbdata_to_pixdata (best, w * h, pixdata);
393
394   XFree (data);
395
396   return TRUE;
397 }
398
399 static void
400 free_pixels (guchar *pixels, gpointer data)
401 {
402   g_free (pixels);
403 }
404
405 static GdkPixbuf*
406 scaled_from_pixdata (guchar *pixdata,
407                      int     w,
408                      int     h,
409                      int     new_w,
410                      int     new_h)
411 {
412   GdkPixbuf *src;
413   GdkPixbuf *dest;
414
415   src = gdk_pixbuf_new_from_data (pixdata,
416                                   GDK_COLORSPACE_RGB,
417                                   TRUE,
418                                   8,
419                                   w, h, w * 4,
420                                   free_pixels,
421                                   NULL);
422
423   if (src == NULL)
424     return NULL;
425
426   if (w != h)
427     {
428       GdkPixbuf *tmp;
429       int size;
430
431       size = MAX (w, h);
432
433       tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
434
435       if (tmp != NULL)
436         {
437           gdk_pixbuf_fill (tmp, 0);
438           gdk_pixbuf_copy_area (src, 0, 0, w, h,
439                                 tmp,
440                                 (size - w) / 2, (size - h) / 2);
441
442           g_object_unref (src);
443           src = tmp;
444         }
445     }
446
447   if (w != new_w || h != new_h)
448     {
449       dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
450
451       g_object_unref (G_OBJECT (src));
452     }
453   else
454     {
455       dest = src;
456     }
457
458   return dest;
459 }
460
461 static gboolean
462 get_window_list (Display  *xdisplay,
463                  Window    xwindow,
464                  Atom      atom,
465                  Window  **windows,
466                  int      *len)
467 {
468   Atom type;
469   int format;
470   gulong nitems;
471   gulong bytes_after;
472   Window *data;
473   int err, result;
474
475   *windows = NULL;
476   *len = 0;
477
478   gdk_error_trap_push ();
479   type = None;
480   result = XGetWindowProperty (xdisplay,
481                                xwindow,
482                                atom,
483                                0, G_MAXLONG,
484                                False, XA_WINDOW, &type, &format, &nitems,
485                                &bytes_after, (void*)&data);
486   XSync (xdisplay, False);
487   err = gdk_error_trap_pop ();
488
489   if (err != Success ||
490       result != Success)
491     return FALSE;
492
493   if (type != XA_WINDOW)
494     {
495       XFree (data);
496       return FALSE;
497     }
498
499   *windows = g_new (Window, nitems);
500   memcpy (*windows, data, sizeof (Window) * nitems);
501   *len = nitems;
502
503   XFree (data);
504
505   return TRUE;
506 }
507
508
509 /* ---------------------------------------------------------------------------------------------------- */
510
511 struct _GtkMountOperationLookupContext
512 {
513   /* Hash from pid (gint) -> XID (gint)
514    *
515    * Note that XIDs are at most 27 bits - however, also note that sizeof(XID) == 8 on
516    * x86_64 - that's just xlib brokenness. So it's safe to stuff the XID into a pointer.
517    */
518   GHashTable *pid_to_window;
519   GdkDisplay *display;
520 };
521
522 GtkMountOperationLookupContext *
523 _gtk_mount_operation_lookup_context_get (GdkDisplay *display)
524 {
525   GtkMountOperationLookupContext *context;
526   Window *mapping;
527   gint mapping_length;
528   gint n;
529
530   context = g_new0 (GtkMountOperationLookupContext, 1);
531
532   context->pid_to_window = g_hash_table_new (g_direct_hash, g_direct_equal);
533   context->display = display;
534
535   mapping = NULL;
536   mapping_length = 0;
537   get_window_list (GDK_DISPLAY_XDISPLAY (context->display),
538                    GDK_ROOT_WINDOW(),
539                    gdk_x11_get_xatom_by_name_for_display (context->display,
540                                                           "_NET_CLIENT_LIST"),
541                    &mapping,
542                    &mapping_length);
543   for (n = 0; n < mapping_length; n++)
544     {
545       gint pid;
546
547       if (!get_cardinal (GDK_DISPLAY_XDISPLAY (context->display),
548                          mapping[n],
549                          gdk_x11_get_xatom_by_name_for_display (context->display,
550                                                                 "_NET_WM_PID"),
551                          &pid))
552         continue;
553
554       g_hash_table_insert (context->pid_to_window,
555                            GINT_TO_POINTER (pid),
556                            GINT_TO_POINTER ((gint) mapping[n]));
557     }
558   g_free (mapping);
559
560   return context;
561 }
562
563 void
564 _gtk_mount_operation_lookup_context_free (GtkMountOperationLookupContext *context)
565 {
566   g_hash_table_unref (context->pid_to_window);
567   g_free (context);
568 }
569
570 /* ---------------------------------------------------------------------------------------------------- */
571
572 #ifdef __linux__
573
574 static GPid
575 pid_get_parent (GPid pid)
576 {
577   GPid ppid;
578   gchar **tokens;
579   gchar *stat_filename;
580   gchar *stat_contents;
581   gsize stat_len;
582
583   ppid = 0;
584   tokens = NULL;
585   stat_contents = NULL;
586   stat_filename = NULL;
587
588   /* fail if trying to get the parent of the init process (no such thing) */
589   if (pid == 1)
590       goto out;
591
592   stat_filename = g_strdup_printf ("/proc/%d/status", pid);
593   if (g_file_get_contents (stat_filename,
594                            &stat_contents,
595                            &stat_len,
596                            NULL))
597     {
598       guint n;
599
600       tokens = g_strsplit (stat_contents, "\n", 0);
601
602       for (n = 0; tokens[n] != NULL; n++)
603         {
604           if (g_str_has_prefix (tokens[n], "PPid:"))
605             {
606               gchar *endp;
607
608               endp = NULL;
609               ppid = strtoll (tokens[n] + sizeof "PPid:" - 1, &endp, 10);
610               if (endp == NULL || *endp != '\0')
611                 {
612                   g_warning ("Error parsing contents of `%s'. Parent pid is malformed.",
613                              stat_filename);
614                   ppid = 0;
615                   goto out;
616                 }
617
618               break;
619             }
620         }
621     }
622
623  out:
624   g_strfreev (tokens);
625   g_free (stat_contents);
626   g_free (stat_filename);
627
628   return ppid;
629 }
630
631 static gchar *
632 pid_get_env (GPid         pid,
633              const gchar *key)
634 {
635   gchar *ret;
636   gchar *env_filename;
637   gchar *env;
638   gsize env_len;
639   gsize key_len;
640   gchar *end;
641
642   ret = NULL;
643
644   key_len = strlen (key);
645
646   env_filename = g_strdup_printf ("/proc/%d/environ", pid);
647   if (g_file_get_contents (env_filename,
648                            &env,
649                            &env_len,
650                            NULL))
651     {
652       guint n;
653
654       /* /proc/<pid>/environ in Linux is split at '\0' points, g_strsplit() can't handle that... */
655       n = 0;
656       while (TRUE)
657         {
658           if (env[n] == '\0' || n >= env_len)
659             break;
660
661           if (g_str_has_prefix (env + n, key) && (*(env + n + key_len) == '='))
662             {
663               ret = g_strdup (env + n + key_len + 1);
664
665               /* skip invalid UTF-8 */
666               if (!g_utf8_validate (ret, -1, (const gchar *) &end))
667                 *end = '\0';
668               break;
669             }
670
671           for (; env[n] != '\0' && n < env_len; n++)
672             ;
673           n++;
674         }
675       g_free (env);
676     }
677   g_free (env_filename);
678
679   return ret;
680 }
681
682 static gchar *
683 pid_get_command_line (GPid pid)
684 {
685   gchar *cmdline_filename;
686   gchar *cmdline_contents;
687   gsize cmdline_len;
688   guint n;
689   gchar *end;
690
691   cmdline_contents = NULL;
692
693   cmdline_filename = g_strdup_printf ("/proc/%d/cmdline", pid);
694   if (!g_file_get_contents (cmdline_filename,
695                             &cmdline_contents,
696                             &cmdline_len,
697                             NULL))
698     goto out;
699
700   /* /proc/<pid>/cmdline separates args by NUL-bytes - replace with spaces */
701   for (n = 0; n < cmdline_len - 1; n++)
702     {
703       if (cmdline_contents[n] == '\0')
704         cmdline_contents[n] = ' ';
705     }
706
707   /* skip invalid UTF-8 */
708   if (!g_utf8_validate (cmdline_contents, -1, (const gchar *) &end))
709       *end = '\0';
710
711  out:
712   g_free (cmdline_filename);
713
714   return cmdline_contents;
715 }
716
717 /* ---------------------------------------------------------------------------------------------------- */
718 #else
719
720 /* TODO: please implement for your OS - must return valid UTF-8 */
721
722 static GPid
723 pid_get_parent (GPid pid)
724 {
725   return 0;
726 }
727
728 static gchar *
729 pid_get_env (GPid         pid,
730              const gchar *key)
731 {
732   return NULL;
733 }
734
735 static gchar *
736 pid_get_command_line (GPid pid)
737 {
738   return NULL;
739 }
740
741 #endif
742
743 /* ---------------------------------------------------------------------------------------------------- */
744
745 static gchar *
746 get_name_for_window_with_pid (GtkMountOperationLookupContext *context,
747                               GPid                            pid)
748 {
749   Window window;
750   Window windowid_window;
751   gchar *ret;
752
753   ret = NULL;
754
755   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
756   if (window == None)
757     {
758       gchar *windowid_value;
759
760       /* check for $WINDOWID (set by terminals) and see if we can get the title that way */
761       windowid_value = pid_get_env (pid, "WINDOWID");
762       if (windowid_value != NULL)
763         {
764           gchar *endp;
765
766           endp = NULL;
767           windowid_window = (Window) g_ascii_strtoll (windowid_value, &endp, 10);
768           if (endp != NULL || *endp == '\0')
769             {
770               window = windowid_window;
771             }
772           g_free (windowid_value);
773         }
774
775       /* otherwise, check for parents */
776       if (window == None)
777         {
778           do
779             {
780               pid = pid_get_parent (pid);
781               if (pid == 0)
782                 break;
783
784               window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
785               if (window != None)
786                 break;
787             }
788           while (TRUE);
789         }
790     }
791
792   if (window != None)
793     {
794       ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
795                                window,
796                                gdk_x11_get_xatom_by_name_for_display (context->display,
797                                                                       "_NET_WM_NAME"));
798       if (ret == NULL)
799         ret = get_utf8_property (GDK_DISPLAY_XDISPLAY (context->display),
800                                  window, gdk_x11_get_xatom_by_name_for_display (context->display,
801                                                                                 "_NET_WM_ICON_NAME"));
802     }
803
804   return ret;
805 }
806
807 /* ---------------------------------------------------------------------------------------------------- */
808
809 static GdkPixbuf *
810 get_pixbuf_for_window_with_pid (GtkMountOperationLookupContext *context,
811                                 GPid                            pid,
812                                 gint                            size_pixels)
813 {
814   Window window;
815   GdkPixbuf *ret;
816
817   ret = NULL;
818
819   window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
820   if (window == None)
821     {
822       /* otherwise, check for parents */
823       do
824         {
825           pid = pid_get_parent (pid);
826           if (pid == 0)
827             break;
828
829           window = GPOINTER_TO_INT (g_hash_table_lookup (context->pid_to_window, GINT_TO_POINTER (pid)));
830           if (window != None)
831             break;
832         }
833       while (TRUE);
834     }
835
836   if (window != None)
837     {
838       gint    width;
839       gint    height;
840       guchar *pixdata;
841
842       if (read_rgb_icon (GDK_DISPLAY_XDISPLAY (context->display),
843                          window,
844                          size_pixels, size_pixels,
845                          &width, &height,
846                          &pixdata))
847         {
848           /* steals pixdata */
849           ret = scaled_from_pixdata (pixdata,
850                                      width, height,
851                                      size_pixels, size_pixels);
852         }
853     }
854
855   return ret;
856 }
857
858 /* ---------------------------------------------------------------------------------------------------- */
859
860 static const gchar *well_known_commands[] =
861 {
862   "less", N_("Terminal Pager"),
863   "top", N_("Top Command"),
864   "bash", N_("Bourne Again Shell"),
865   "sh", N_("Bourne Shell"),
866   "zsh", N_("Z Shell"),
867   NULL,
868 };
869
870 gboolean
871 _gtk_mount_operation_lookup_info (GtkMountOperationLookupContext *context,
872                                   GPid                            pid,
873                                   gint                            size_pixels,
874                                   gchar                         **out_name,
875                                   gchar                         **out_command_line,
876                                   GdkPixbuf                     **out_pixbuf)
877 {
878   g_return_val_if_fail (out_name != NULL && *out_name == NULL, FALSE);
879   g_return_val_if_fail (out_command_line != NULL && *out_command_line == NULL, FALSE);
880   g_return_val_if_fail (out_pixbuf != NULL && *out_pixbuf == NULL, FALSE);
881
882   /* We perform two different lookups for name and icon size.. this is
883    * because we want the name from the window with WINDOWID and this
884    * normally does not give you an icon
885    *
886    * (the canonical example is a tab in gnome-terminal - the shell/command running
887    *  in the shell will have WINDOWID set - but this window won't have an icon - so
888    *  we want to continue up until the gnome-terminal window so we can get that icon)
889    */
890
891   *out_command_line = pid_get_command_line (pid);
892
893   *out_name = get_name_for_window_with_pid (context, pid);
894
895   *out_pixbuf = get_pixbuf_for_window_with_pid (context, pid, size_pixels);
896
897   /* if we didn't manage to find the name via X, fall back to the basename
898    * of the first element of the command line and, for maximum geek-comfort,
899    * map a few well-known commands to proper translated names
900    */
901   if (*out_name == NULL && *out_command_line != NULL &&
902       strlen (*out_command_line) > 0 && (*out_command_line)[0] != ' ')
903     {
904       guint n;
905       gchar *s;
906       gchar *p;
907
908       /* find the first character after the first argument */
909       s = strchr (*out_command_line, ' ');
910       if (s == NULL)
911         s = *out_command_line + strlen (*out_command_line);
912
913       for (p = s; p > *out_command_line; p--)
914         {
915           if (*p == '/')
916             {
917               p++;
918               break;
919             }
920         }
921
922       *out_name = g_strndup (p, s - p);
923
924       for (n = 0; well_known_commands[n] != NULL; n += 2)
925         {
926           /* sometimes the command is prefixed with a -, e.g. '-bash' instead
927            * of 'bash' - handle that as well
928            */
929           if ((strcmp (well_known_commands[n], *out_name) == 0) ||
930               ((*out_name)[0] == '-' && (strcmp (well_known_commands[n], (*out_name) + 1) == 0)))
931             {
932               g_free (*out_name);
933               *out_name = g_strdup (_(well_known_commands[n+1]));
934               break;
935             }
936         }
937     }
938
939   return TRUE;
940 }
941
942 gboolean
943 _gtk_mount_operation_kill_process (GPid      pid,
944                                    GError  **error)
945 {
946   gboolean ret;
947
948   ret = TRUE;
949
950   if (kill ((pid_t) pid, SIGTERM) != 0)
951     {
952       /* TODO: On EPERM, we could use a setuid helper using polkit (very easy to implement
953        *       via pkexec(1)) to allow the user to e.g. authenticate to gain the authorization
954        *       to kill the process. But that's not how things currently work.
955        */
956
957       ret = FALSE;
958       g_set_error (error,
959                    G_IO_ERROR,
960                    g_io_error_from_errno (errno),
961                    _("Cannot end process with pid %d: %s"),
962                    pid,
963                    strerror (errno));
964     }
965
966   return ret;
967 }