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