Bug Summary

File:battstat/battstat-upower.c
Warning:line 102, column 17
Value stored to 'cancellable' during its initialization is never read

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 battstat-upower.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 -pic-is-pie -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 -fdebug-compilation-dir=/rootdir/battstat -fcoverage-compilation-dir=/rootdir/battstat -resource-dir /usr/lib/llvm-21/lib/clang/21 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/cafe-panel-4.0/libcafe-panel-applet -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/atk-1.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/libupower-glib -I /usr/include/polkit-1 -I /usr/include/gio-unix-2.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I ./apmlib/ -D G_LOG_DOMAIN="battstat_applet" -D BATTSTAT_MENU_UI_DIR="/usr/share/cafe/ui" -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker security.ArrayBound -analyzer-checker unix.cstring.NotNullTerminated -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -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/2026-03-14-184004-83912-1 -x c battstat-upower.c
1/*
2 * Copyright (C) 2010 by Joachim Breitner <mail@joachim-breitner.de>
3 *
4 * Based on battstat-hal.c:
5 * Copyright (C) 2005 by Ryan Lortie <desrt@desrt.ca>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * $Id$
22 */
23
24#include <config.h>
25
26#ifdef HAVE_UPOWER1
27
28#include <upower.h>
29#include <math.h>
30
31#include "battstat-upower.h"
32
33static UpClient *upc;
34static void (*status_updated_callback) (void);
35
36
37/* status_updated_callback() can not be called directly because at the time of
38 * the device-remove signal, the device is not actually removed from the list
39 * of devices known to the up_client object (see libupower-glib/up-client.c in
40 * upower). Waiting for the next idle timer works around this issue and has has
41 * the additionaly benefit of possibly running status_updated_callback only
42 * once when several events happen very soon after each other.
43 */
44static gboolean status_update_scheduled;
45
46static gboolean
47update_status_idle (gpointer junk G_GNUC_UNUSED__attribute__ ((__unused__)))
48{
49 if (status_updated_callback)
50 status_updated_callback ();
51
52 return status_update_scheduled = FALSE(0);
53}
54
55static void
56schedule_status_callback (void)
57{
58 if (status_update_scheduled)
59 return;
60
61 status_update_scheduled = TRUE(!(0));
62 g_idle_add (update_status_idle, NULL((void*)0));
63}
64
65static void
66device_cb (UpClient *client G_GNUC_UNUSED__attribute__ ((__unused__)),
67 UpDevice *device G_GNUC_UNUSED__attribute__ ((__unused__)),
68 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
69{
70 schedule_status_callback();
71}
72
73#if UP_CHECK_VERSION (0, 99, 0)((1) > (0) || ((1) == (0) && (91) > (99)) || ((
1) == (0) && (91) == (99) && (1) >= (0)))
74static void
75device_removed_cb (UpClient *client G_GNUC_UNUSED__attribute__ ((__unused__)),
76 const gchar *object_path G_GNUC_UNUSED__attribute__ ((__unused__)),
77 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
78{
79 schedule_status_callback();
80}
81#endif
82
83/* ---- public functions ---- */
84
85char *
86battstat_upower_initialise (void (*callback) (void))
87{
88 char *error_str;
89 int i, num;
90
91 status_updated_callback = callback;
92#if UP_CHECK_VERSION (0, 99, 0)((1) > (0) || ((1) == (0) && (91) > (99)) || ((
1) == (0) && (91) == (99) && (1) >= (0)))
93 GPtrArray *devices;
94#endif
95
96 if( upc != NULL((void*)0) )
97 return g_strdup( "Already initialised!" )g_strdup_inline ("Already initialised!");
98
99 if( (upc = up_client_new() ) == NULL((void*)0) )
100 goto error_out;
101
102 GCancellable *cancellable = g_cancellable_new();
Value stored to 'cancellable' during its initialization is never read
103 GError *gerror;
104
105#if UP_CHECK_VERSION(0, 99, 0)((1) > (0) || ((1) == (0) && (91) > (99)) || ((
1) == (0) && (91) == (99) && (1) >= (0)))
106 devices = up_client_get_devices2(upc);
107 if (!devices) {
108 goto error_shutdownclient;
109 }
110 g_ptr_array_unref(devices);
111#else
112 if (! up_client_enumerate_devices_sync( upc, cancellable, &gerror ) ) {
113 sprintf(error_str, "Unable to enumerate upower devices: %s\n", gerror->message);
114 goto error_shutdownclient;
115 }
116#endif
117
118 g_signal_connect_after( upc, "device-added", G_CALLBACK (device_cb), NULL )g_signal_connect_data ((upc), ("device-added"), (((GCallback)
(device_cb))), (((void*)0)), ((void*)0), G_CONNECT_AFTER)
;
119#if UP_CHECK_VERSION(0, 99, 0)((1) > (0) || ((1) == (0) && (91) > (99)) || ((
1) == (0) && (91) == (99) && (1) >= (0)))
120 g_signal_connect_after( upc, "device-removed", G_CALLBACK (device_removed_cb), NULL )g_signal_connect_data ((upc), ("device-removed"), (((GCallback
) (device_removed_cb))), (((void*)0)), ((void*)0), G_CONNECT_AFTER
)
;
121#else
122 g_signal_connect_after( upc, "device-changed", G_CALLBACK (device_cb), NULL )g_signal_connect_data ((upc), ("device-changed"), (((GCallback
) (device_cb))), (((void*)0)), ((void*)0), G_CONNECT_AFTER)
;
123 g_signal_connect_after( upc, "device-removed", G_CALLBACK (device_cb), NULL )g_signal_connect_data ((upc), ("device-removed"), (((GCallback
) (device_cb))), (((void*)0)), ((void*)0), G_CONNECT_AFTER)
;
124#endif
125
126 return NULL((void*)0);
127
128error_shutdownclient:
129 g_object_unref( upc );
130 upc = NULL((void*)0);
131
132error_out:
133 return "Can not initialize upower";
134}
135
136void
137battstat_upower_cleanup( void )
138{
139 if( upc == NULL((void*)0) )
140 return;
141
142 g_object_unref( upc );
143 upc = NULL((void*)0);
144}
145
146#include "battstat.h"
147
148/* This function currently exists to allow the multiple batteries supported
149 * by the upower backend to appear as a single composite battery device (since
150 * at the current time this is all that battstat supports).
151 *
152 * This entire function is filled with logic to make multiple batteries
153 * appear as one "composite" battery. Comments included as appropriate.
154 *
155 * For more information about some of the assumptions made in the following
156 * code please see the following mailing list post and the resulting thread:
157 *
158 * http://lists.freedesktop.org/archives/hal/2005-July/002841.html
159 */
160void
161battstat_upower_get_battery_info( BatteryStatus *status )
162{
163
164 GPtrArray *devices = up_client_get_devices2( upc );
165
166 /* The calculation to get overall percentage power remaining is as follows:
167 *
168 * Sum( Current charges ) / Sum( Full Capacities )
169 *
170 * We can't just take an average of all of the percentages since this
171 * doesn't deal with the case that one battery might have a larger
172 * capacity than the other.
173 *
174 * In order to do this calculation, we need to keep a running total of
175 * current charge and full capacities.
176 */
177 double current_charge_total = 0, full_capacity_total = 0;
178
179 /* Record the time remaining as reported by upower. This is used in the event
180 * that the system has exactly one battery (since, then, upower is capable
181 * of providing an accurate time remaining report and we should trust it.)
182 */
183 gint64 remaining_time = 0;
184
185 /* The total (dis)charge rate of the system is the sum of the rates of
186 * the individual batteries.
187 */
188 double rate_total = 0;
189
190 /* We need to know if we should report the composite battery as present
191 * at all. The logic is that if at least one actual battery is installed
192 * then the composite battery will be reported to exist.
193 */
194 int present = 0;
195
196 /* We need to know if we are on AC power or not. Eventually, we can look
197 * at the AC adaptor upower devices to determine that. For now, we assume that
198 * if any battery is discharging then we must not be on AC power. Else, by
199 * default, we must be on AC.
200 */
201 int on_ac_power = 1;
202
203 /* Finally, we consider the composite battery to be "charging" if at least
204 * one of the actual batteries in the system is charging.
205 */
206 int charging = 0;
207
208 /* A list iterator. */
209 GSList *item;
210
211 /* For each physical battery bay... */
212 int i;
213 for( i = 0; i < devices->len; i++ )
214 {
215 UpDevice *upd = g_ptr_array_index( devices, i )((devices)->pdata)[i];
216
217 int type, state;
218 double current_charge, full_capacity, rate;
219 gint64 time_to_full, time_to_empty;
220
221 g_object_get( upd,
222 "kind", &type,
223 "state", &state,
224 "energy", &current_charge,
225 "energy-full", &full_capacity,
226 "energy-rate", &rate,
227 "time-to-full", &time_to_full,
228 "time-to-empty", &time_to_empty,
229 NULL((void*)0) );
230
231 /* Only count batteries here */
232
233 if (type != UP_DEVICE_KIND_BATTERY)
234 continue;
235
236 /* At least one battery present -> composite battery is present. */
237 present++;
238
239 /* At least one battery charging -> composite battery is charging. */
240 if( state == UP_DEVICE_STATE_CHARGING )
241 charging = 1;
242
243 /* At least one battery is discharging -> we're not on AC. */
244 if( state == UP_DEVICE_STATE_DISCHARGING )
245 on_ac_power = 0;
246
247 /* Sum the totals for current charge, design capacity, (dis)charge rate. */
248 current_charge_total += current_charge;
249 full_capacity_total += full_capacity;
250 rate_total += rate;
251
252 /* Record remaining time too, incase this is the only battery. */
253 remaining_time = (state == UP_DEVICE_STATE_DISCHARGING ? time_to_empty : time_to_full);
254 }
255
256 if( !present || full_capacity_total <= 0 || (charging && !on_ac_power) )
257 {
258 /* Either no battery is present or something has gone horribly wrong.
259 * In either case we must return that the composite battery is not
260 * present.
261 */
262 status->present = FALSE(0);
263 status->percent = 0;
264 status->minutes = -1;
265 status->on_ac_power = TRUE(!(0));
266 status->charging = FALSE(0);
267
268 g_ptr_array_unref( devices );
269 return;
270 }
271
272 /* Else, our composite battery is present. */
273 status->present = TRUE(!(0));
274
275 /* As per above, overall charge is:
276 *
277 * Sum( Current charges ) / Sum( Full Capacities )
278 */
279 status->percent = ( current_charge_total / full_capacity_total ) * 100.0 + 0.5;
280
281 if( present == 1 )
282 {
283 /* In the case of exactly one battery, report the time remaining figure
284 * from upower directly since it might have come from an authorative source
285 * (ie: the PMU or APM subsystem).
286 *
287 * upower gives remaining time in seconds with a 0 to mean that the
288 * remaining time is unknown. Battstat uses minutes and -1 for
289 * unknown time remaining.
290 */
291
292 if( remaining_time == 0 )
293 status->minutes = -1;
294 else
295 status->minutes = (remaining_time + 30) / 60;
296 }
297 /* Rest of cases to deal with multiple battery systems... */
298 else if( !on_ac_power && rate_total != 0 )
299 {
300 /* Then we're discharging. Calculate time remaining until at zero. */
301
302 double remaining;
303
304 remaining = current_charge_total;
305 remaining /= rate_total;
306 status->minutes = (int) floor( remaining * 60.0 + 0.5 );
307 }
308 else if( charging && rate_total != 0 )
309 {
310 /* Calculate time remaining until charged. For systems with more than
311 * one battery, this code is very approxicafe. The assumption is that if
312 * one battery reaches full charge before the other that the other will
313 * start charging faster due to the increase in available power (similar
314 * to how a laptop will charge faster if you're not using it).
315 */
316
317 double remaining;
318
319 remaining = full_capacity_total - current_charge_total;
320 if( remaining < 0 )
321 remaining = 0;
322 remaining /= rate_total;
323
324 status->minutes = (int) floor( remaining * 60.0 + 0.5 );
325 }
326 else
327 {
328 /* On AC power and not charging -or- rate is unknown. */
329 status->minutes = -1;
330 }
331
332 /* These are simple and well-explained above. */
333 status->charging = charging;
334 status->on_ac_power = on_ac_power;
335
336 g_ptr_array_unref( devices );
337}
338
339void
340error_dialog( const char *fmt , ...)
341{
342 va_list ap;
343 va_start(ap, fmt)__builtin_va_start(ap, fmt);
344 char str[1000];
345 vsprintf(str, fmt, ap);
346 va_end(ap)__builtin_va_end(ap);
347 CtkWidget *dialog;
348
349 dialog = ctk_message_dialog_new( NULL((void*)0), 0, CTK_MESSAGE_ERROR,
350 CTK_BUTTONS_OK, "%s", str);
351
352 g_signal_connect_swapped( G_OBJECT (dialog), "response",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dialog)), (((GType) ((20) << (2)))
)))))), ("response"), (((GCallback) (ctk_widget_destroy))), (
((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), (((GType) ((20) << (2))))))))), ((void*)
0), G_CONNECT_SWAPPED)
353 G_CALLBACK (ctk_widget_destroy),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dialog)), (((GType) ((20) << (2)))
)))))), ("response"), (((GCallback) (ctk_widget_destroy))), (
((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), (((GType) ((20) << (2))))))))), ((void*)
0), G_CONNECT_SWAPPED)
354 G_OBJECT (dialog) )g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dialog)), (((GType) ((20) << (2)))
)))))), ("response"), (((GCallback) (ctk_widget_destroy))), (
((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), (((GType) ((20) << (2))))))))), ((void*)
0), G_CONNECT_SWAPPED)
;
355
356 ctk_widget_show_all( dialog );
357}
358
359#endif /* HAVE_UPOWER */