Bug Summary

File:ctk/ctkmountoperation-x11.c
Warning:line 1008, column 15
Out of bound memory access (access exceeds upper limit of memory block)

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkmountoperation-x11.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-171502-43637-1 -x c ctkmountoperation-x11.c
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
51static gboolean get_window_list (CdkDisplay *display,
52 Window xwindow,
53 Atom atom,
54 Window **windows,
55 int *len);
56
57static char* get_utf8_property (CdkDisplay *display,
58 Window xwindow,
59 Atom atom);
60
61static gboolean get_cardinal (CdkDisplay *display,
62 Window xwindow,
63 Atom atom,
64 int *val);
65
66static 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
75static gboolean
76get_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
118static char*
119get_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
175static gboolean
176find_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
207static gboolean
208find_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
303static void
304argbdata_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
337static gboolean
338read_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
395static void
396free_pixels (guchar *pixels,
397 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
398{
399 g_free (pixels);
400}
401
402static GdkPixbuf*
403scaled_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
458static gboolean
459get_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
508struct _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
519CtkMountOperationLookupContext *
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
560void
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
571static GPid
572pid_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
628static gchar *
629pid_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
679static gchar *
680pid_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
720static GPid
721pid_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
742static gchar *
743pid_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
782static gchar *
783pid_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
814static GPid
815pid_get_parent (GPid pid)
816{
817 return 0;
818}
819
820static gchar *
821pid_get_env (GPid pid,
822 const gchar *key)
823{
824 return NULL((void*)0);
825}
826
827static gchar *
828pid_get_command_line (GPid pid)
829{
830 return NULL((void*)0);
831}
832
833#endif
834
835/* ---------------------------------------------------------------------------------------------------- */
836
837static gchar *
838get_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
901static GdkPixbuf *
902get_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
952static 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
963gboolean
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)
;
1
Assuming 'out_name' is not equal to null
2
Assuming the condition is true
3
Taking true branch
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)
;
4
Loop condition is false. Exiting loop
5
Assuming 'out_command_line' is not equal to null
6
Assuming the condition is true
7
Taking true branch
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)
;
8
Loop condition is false. Exiting loop
9
Assuming 'out_pixbuf' is not equal to null
10
Assuming the condition is true
11
Taking true branch
12
Loop condition is false. Exiting loop
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) &&
13
Assuming the condition is true
14
Assuming the condition is true
17
Taking true branch
995 strlen (*out_command_line) > 0 && (*out_command_line)[0] != ' ')
15
Assuming the condition is true
16
Assuming the condition is true
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))
18
Assuming 's' is not equal to NULL
19
Taking false branch
1004 s = *out_command_line + strlen (*out_command_line);
1005
1006 for (p = s; p > *out_command_line; p--)
20
Assuming the condition is true
21
Loop condition is true. Entering loop body
24
Loop condition is true. Entering loop body
1007 {
1008 if (*p == '/')
22
Assuming the condition is false
23
Taking false branch
25
Out of bound memory access (access exceeds upper limit of memory block)
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
1035gboolean
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}