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