Bug Summary

File:/shared/playproj/i2c/src/libmain/api_base.c
Warning:line 700, column 11
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'parsed_cmd')

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 api_base.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=/shared/playproj/i2c/src/libmain -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I ../../src -I ../../src/public -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir=/shared/playproj/i2c/src/libmain -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o api_base.plist -x c api_base.c
1/** @file api_base.c
2 *
3 * C API base functions.
4 */
5
6// Copyright (C) 2015-2023 Sanford Rockowitz <rockowitz@minsoft.com>
7// SPDX-License-Identifier: GPL-2.0-or-later
8
9#include "config.h"
10
11#define _GNU_SOURCE1 1
12#include <assert.h>
13#include <dlfcn.h> // _GNU_SOURCE for dladdr()
14#include <errno(*__errno_location ()).h>
15#include <glib-2.0/glib.h>
16#include <signal.h>
17#include <string.h>
18#include <syslog.h>
19
20#include "public/ddcutil_c_api.h"
21
22#include "util/ddcutil_config_file.h"
23#include "util/debug_util.h"
24#include "util/file_util.h"
25#include "util/report_util.h"
26#include "util/sysfs_filter_functions.h"
27#include "util/xdg_util.h"
28
29#include "base/base_services.h"
30#include "base/build_info.h"
31#include "base/core_per_thread_settings.h"
32#include "base/core.h"
33#include "base/dsa2.h"
34#include "base/parms.h"
35#include "base/per_display_data.h"
36#include "base/per_thread_data.h"
37#include "base/rtti.h"
38#include "base/trace_control.h"
39#include "base/tuned_sleep.h"
40
41#include "cmdline/cmd_parser.h"
42#include "cmdline/parsed_cmd.h"
43
44#include "i2c/i2c_bus_core.h" // for testing watch_devices
45#include "i2c/i2c_display_lock.h"
46#include "i2c/i2c_execute.h" // for i2c_set_addr()
47
48#include "ddc/ddc_common_init.h"
49#include "ddc/ddc_displays.h"
50#include "ddc/ddc_multi_part_io.h"
51#include "ddc/ddc_packet_io.h"
52#include "ddc/ddc_serialize.h"
53#include "ddc/ddc_services.h"
54#include "ddc/ddc_try_data.h"
55#include "ddc/ddc_vcp.h"
56#include "ddc/ddc_watch_displays.h"
57
58#include "libmain/api_error_info_internal.h"
59#include "libmain/api_base_internal.h"
60#include "libmain/api_services_internal.h"
61
62//
63// Forward Declarations
64//
65
66void init_api_base();
67
68//
69// Globals
70//
71
72bool_Bool library_initialized = false0;
73bool_Bool library_initialization_failed = false0;
74static bool_Bool client_opened_syslog = false0;
75static bool_Bool enable_init_msgs = false0;
76static FILE * flog = NULL((void*)0);
77static DDCA_Stats_Type requested_stats = 0;
78static bool_Bool per_display_stats = false0;
79static bool_Bool dsa_detail_stats;
80
81
82//
83// Precondition Failure
84//
85
86DDCI_Api_Precondition_Failure_Mode api_failure_mode = DDCI_PRECOND_STDERR_RETURN;
87
88#ifdef UNUSED
89static DDCI_Api_Precondition_Failure_Mode
90ddci_set_precondition_failure_mode(
91 DDCI_Api_Precondition_Failure_Mode failure_mode)
92{
93 DDCI_Api_Precondition_Failure_Mode old = api_failure_mode;
94 api_failure_mode = failure_mode;
95 return old;
96}
97
98static DDCI_Api_Precondition_Failure_Mode
99ddci_get_precondition_failure_mode()
100{
101 return api_failure_mode;
102}
103#endif
104
105
106//
107// Library Build Information
108//
109
110DDCA_Ddcutil_Version_Spec
111ddca_ddcutil_version(void) {
112 static DDCA_Ddcutil_Version_Spec vspec = {255,255,255};
113 static bool_Bool vspec_init = false0;
114
115 if (!vspec_init) {
116#ifndef NDEBUG
117 int ct =
118#endif
119 sscanf(get_base_ddcutil_version(),
120 "%hhu.%hhu.%hhu", &vspec.major, &vspec.minor, &vspec.micro);
121#ifndef NDEBUG
122 assert(ct == 3)((void) sizeof ((ct == 3) ? 1 : 0), __extension__ ({ if (ct ==
3) ; else __assert_fail ("ct == 3", "api_base.c", 122, __extension__
__PRETTY_FUNCTION__); }))
;
123#endif
124 vspec_init = true1;
125 }
126 DBGMSG("Returning: %d.%d.%d", vspec.major, vspec.minor, vspec.micro)dbgtrc(DDCA_TRC_ALL, 0x00, __func__, 126, "api_base.c", "Returning: %d.%d.%d"
, vspec.major, vspec.minor, vspec.micro)
;
127 return vspec;
128}
129
130
131/** Returns the ddcutil version as a string in the form "major.minor.micro".
132 *
133 */
134const char *
135ddca_ddcutil_version_string(void) {
136 return get_base_ddcutil_version();
137}
138
139
140// Returns the full ddcutil version as a string that may be suffixed with an extension
141const char *
142ddca_ddcutil_extended_version_string(void) {
143 return get_full_ddcutil_version();
144}
145
146
147#ifdef UNUSED
148// Indicates whether the ddcutil library was built with support for USB connected monitors.
149bool_Bool
150ddca_built_with_usb(void) {
151#ifdef ENABLE_USB1
152 return true1;
153#else
154 return false0;
155#endif
156}
157#endif
158
159// Alternative to individual ddca_built_with...() functions.
160// conciseness vs documentability
161// how to document bits? should doxygen doc be in header instead?
162
163DDCA_Build_Option_Flags
164ddca_build_options(void) {
165 uint8_t result = 0x00;
166#ifdef ENABLE_USB1
167 result |= DDCA_BUILT_WITH_USB;
168#endif
169#ifdef FAILSIM_ENABLED
170 result |= DDCA_BUILT_WITH_FAILSIM;
171#endif
172 // DBGMSG("Returning 0x%02x", result);
173 return result;
174}
175
176
177const char *
178ddca_libddcutil_filename(void) {
179 Dl_info info = {NULL((void*)0),NULL((void*)0),NULL((void*)0),NULL((void*)0)};
180 static char fullname[PATH_MAX4096];
181 static char * p = NULL((void*)0);
182 if (!p) {
183 dladdr(ddca_build_options, &info);
184 p = realpath(info.dli_fname, fullname);
185 assert(p == fullname)((void) sizeof ((p == fullname) ? 1 : 0), __extension__ ({ if
(p == fullname) ; else __assert_fail ("p == fullname", "api_base.c"
, 185, __extension__ __PRETTY_FUNCTION__); }))
;
186 }
187 return p;
188}
189
190
191Error_Info* perform_parse(
192 int new_argc,
193 char ** new_argv,
194 char * combined,
195 Parsed_Cmd ** parsed_cmd_loc)
196{
197 GPtrArray * errmsgs = g_ptr_array_new_with_free_func(g_free);
198 bool_Bool debug = false0;
199
200 Error_Info * result = NULL((void*)0);
201 DBGF(debug, "Calling parse_command(), errmsgs=%p\n", errmsgs)do { if (debug) simple_dbgmsg(debug, __func__, 201, "api_base.c"
, "Calling parse_command(), errmsgs=%p\n", errmsgs); } while(
0)
;
202 *parsed_cmd_loc = parse_command(new_argc, new_argv, MODE_LIBDDCUTIL, errmsgs);
203 DBGF(debug, "*parsed_cmd_loc=%p, errmsgs->len=%d", *parsed_cmd_loc, errmsgs->len)do { if (debug) simple_dbgmsg(debug, __func__, 203, "api_base.c"
, "*parsed_cmd_loc=%p, errmsgs->len=%d", *parsed_cmd_loc, errmsgs
->len); } while(0)
;
204 ASSERT_IFF(*parsed_cmd_loc, errmsgs->len == 0)((void) sizeof ((( (*parsed_cmd_loc) && (errmsgs->
len == 0) ) || ( !(*parsed_cmd_loc) && !(errmsgs->
len == 0) )) ? 1 : 0), __extension__ ({ if (( (*parsed_cmd_loc
) && (errmsgs->len == 0) ) || ( !(*parsed_cmd_loc)
&& !(errmsgs->len == 0) )) ; else __assert_fail (
"( (*parsed_cmd_loc) && (errmsgs->len == 0) ) || ( !(*parsed_cmd_loc) && !(errmsgs->len == 0) )"
, "api_base.c", 204, __extension__ __PRETTY_FUNCTION__); }))
;
205 if (!*parsed_cmd_loc) {
206 if (test_emit_syslog(DDCA_SYSLOG_ERROR)) {
207 syslog(LOG_ERR3, "Invalid option string: %s", combined);
208 for (int ndx = 0; ndx < errmsgs->len; ndx++) {
209 char * msg = g_ptr_array_index(errmsgs,ndx)((errmsgs)->pdata)[ndx];
210 syslog(LOG_ERR3, "%s", msg);
211 }
212 }
213 result = ERRINFO_NEW(DDCRC_INVALID_CONFIG_FILE, "Invalid option string: %s", combined)errinfo_new((-(3000 +28) ), __func__, "Invalid option string: %s"
, combined)
;
214 for (int ndx = 0; ndx < errmsgs->len; ndx++) {
215 char * msg = g_ptr_array_index(errmsgs, ndx)((errmsgs)->pdata)[ndx];
216 errinfo_add_cause(result, errinfo_new(DDCRC_INVALID_CONFIG_FILE(-(3000 +28) ), __func__, msg));
217 }
218 }
219 else {
220 if (debug)
221 dbgrpt_parsed_cmd(*parsed_cmd_loc, 1);
222 }
223 g_ptr_array_free(errmsgs, true1);
224 ASSERT_IFF(*parsed_cmd_loc, !result)((void) sizeof ((( (*parsed_cmd_loc) && (!result) ) ||
( !(*parsed_cmd_loc) && !(!result) )) ? 1 : 0), __extension__
({ if (( (*parsed_cmd_loc) && (!result) ) || ( !(*parsed_cmd_loc
) && !(!result) )) ; else __assert_fail ("( (*parsed_cmd_loc) && (!result) ) || ( !(*parsed_cmd_loc) && !(!result) )"
, "api_base.c", 224, __extension__ __PRETTY_FUNCTION__); }))
;
225 return result;
226
227}
228
229
230static inline void emit_parse_info_msg(const char * msg, GPtrArray* infomsgs) {
231 if (infomsgs)
232 g_ptr_array_add(infomsgs, g_strdup_printf("%s%s", "libddcutil: ", msg));
233 SYSLOG2(DDCA_SYSLOG_NOTICE,"%s", msg)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE
); if (syslog_priority >= 0) { syslog(syslog_priority, "%s"
, msg); } } } while(0)
;
234}
235
236
237//
238// Initialization
239//
240static Error_Info *
241get_parsed_libmain_config(const char * libopts_string,
242 bool_Bool disable_config_file,
243 GPtrArray* infomsgs,
244 Parsed_Cmd** parsed_cmd_loc)
245{
246 bool_Bool debug = false0;
247 DBGF(debug, "Starting. disable_config_file = %s, libopts_string = %sn",do { if (debug) simple_dbgmsg(debug, __func__, 248, "api_base.c"
, "Starting. disable_config_file = %s, libopts_string = %sn",
sbool(disable_config_file), libopts_string); } while(0)
248 sbool(disable_config_file), libopts_string)do { if (debug) simple_dbgmsg(debug, __func__, 248, "api_base.c"
, "Starting. disable_config_file = %s, libopts_string = %sn",
sbool(disable_config_file), libopts_string); } while(0)
;
249
250 char * msg = g_strdup_printf("Options passed from client: %s",
251 (libopts_string) ? libopts_string : "");
252 emit_parse_info_msg(msg, infomsgs);
253 free(msg);
254
255 Error_Info * result = NULL((void*)0);
256 *parsed_cmd_loc = NULL((void*)0);
257
258 char ** libopts_tokens = NULL((void*)0);
259 int libopts_token_ct = 0;
260 if (libopts_string) {
261 libopts_token_ct = tokenize_options_line(libopts_string, &libopts_tokens);
262 DBGF(debug, "libopts_token_ct = %d, libopts_tokens=%p:", libopts_token_ct,libopts_tokens)do { if (debug) simple_dbgmsg(debug, __func__, 262, "api_base.c"
, "libopts_token_ct = %d, libopts_tokens=%p:", libopts_token_ct
,libopts_tokens); } while(0)
;
263 if (debug)
264 ntsa_show(libopts_tokens);
265 }
266 Null_Terminated_String_Array cmd_name_array = calloc(2 + libopts_token_ct, sizeof(char*));
267 cmd_name_array[0] = strdup("libddcutil"); // so libddcutil not a special case for parser
268 int ndx = 0;
269 for (; ndx < libopts_token_ct; ndx++)
270 cmd_name_array[ndx+1] = g_strdup(libopts_tokens[ndx])g_strdup_inline (libopts_tokens[ndx]);
271 cmd_name_array[ndx+1] = NULL((void*)0);
272 ntsa_free(libopts_tokens,true1);
273
274 DBGF(debug, "cmd_name_array=%p, cmd_name_array[1]=%p -> %s",do { if (debug) simple_dbgmsg(debug, __func__, 275, "api_base.c"
, "cmd_name_array=%p, cmd_name_array[1]=%p -> %s", cmd_name_array
, cmd_name_array[0], cmd_name_array[0]); } while(0)
275 cmd_name_array, cmd_name_array[0], cmd_name_array[0])do { if (debug) simple_dbgmsg(debug, __func__, 275, "api_base.c"
, "cmd_name_array=%p, cmd_name_array[1]=%p -> %s", cmd_name_array
, cmd_name_array[0], cmd_name_array[0]); } while(0)
;
276
277 char ** new_argv = NULL((void*)0);
278 int new_argc = 0;
279 char * untokenized_option_string = NULL((void*)0);
280
281 if (disable_config_file) {
282 DBGF(debug, "config file disabled")do { if (debug) simple_dbgmsg(debug, __func__, 282, "api_base.c"
, "config file disabled"); } while(0)
;
283 new_argv = ntsa_copy(cmd_name_array, true1);
284 new_argc = ntsa_length(cmd_name_array);
285 ntsa_free(cmd_name_array, true1);
286 }
287 else {
288 GPtrArray * errmsgs = g_ptr_array_new_with_free_func(g_free);
289 char * config_fn = NULL((void*)0);
290 DBGF(debug, "Calling apply_config_file()...")do { if (debug) simple_dbgmsg(debug, __func__, 290, "api_base.c"
, "Calling apply_config_file()..."); } while(0)
;
291 int apply_config_rc = apply_config_file(
292 "libddcutil", // use this section of config file
293 ntsa_length(cmd_name_array), cmd_name_array,
294 &new_argc,
295 &new_argv,
296 &untokenized_option_string,
297 &config_fn,
298 errmsgs);
299 ntsa_free(cmd_name_array, true1);
300 assert(apply_config_rc <= 0)((void) sizeof ((apply_config_rc <= 0) ? 1 : 0), __extension__
({ if (apply_config_rc <= 0) ; else __assert_fail ("apply_config_rc <= 0"
, "api_base.c", 300, __extension__ __PRETTY_FUNCTION__); }))
;
301 ASSERT_IFF(apply_config_rc == 0, errmsgs->len == 0)((void) sizeof ((( (apply_config_rc == 0) && (errmsgs
->len == 0) ) || ( !(apply_config_rc == 0) && !(errmsgs
->len == 0) )) ? 1 : 0), __extension__ ({ if (( (apply_config_rc
== 0) && (errmsgs->len == 0) ) || ( !(apply_config_rc
== 0) && !(errmsgs->len == 0) )) ; else __assert_fail
("( (apply_config_rc == 0) && (errmsgs->len == 0) ) || ( !(apply_config_rc == 0) && !(errmsgs->len == 0) )"
, "api_base.c", 301, __extension__ __PRETTY_FUNCTION__); }))
;
302 // DBGF(debug, "Calling ntsa_free(cmd_name_array=%p", cmd_name_array);
303
304 DBGF(debug, "apply_config_file() returned: %d (%s), new_argc=%d, new_argv=%p:",do { if (debug) simple_dbgmsg(debug, __func__, 305, "api_base.c"
, "apply_config_file() returned: %d (%s), new_argc=%d, new_argv=%p:"
, apply_config_rc, psc_desc(apply_config_rc), new_argc, new_argv
); } while(0)
305 apply_config_rc, psc_desc(apply_config_rc), new_argc, new_argv)do { if (debug) simple_dbgmsg(debug, __func__, 305, "api_base.c"
, "apply_config_file() returned: %d (%s), new_argc=%d, new_argv=%p:"
, apply_config_rc, psc_desc(apply_config_rc), new_argc, new_argv
); } while(0)
;
306
307 if (apply_config_rc == -EBADMSG74) {
308 result = errinfo_new(DDCRC_INVALID_CONFIG_FILE(-(3000 +28) ), __func__,
309 "Error(s) processing configuration file: %s", config_fn);
310 for (int ndx = 0; ndx < errmsgs->len; ndx++) {
311 errinfo_add_cause(result,
312 errinfo_new(DDCRC_INVALID_CONFIG_FILE(-(3000 +28) ), __func__, g_ptr_array_index(errmsgs, ndx)((errmsgs)->pdata)[ndx]));
313 }
314
315 }
316 // else if (apply_config_rc == -ENOENT) {
317 // result = errinfo_new(-ENOENT, __func__, "Configuration file not found");
318 // }
319 else if (apply_config_rc < 0) {
320 result = errinfo_new(apply_config_rc, __func__,
321 "Unexpected error reading configuration file: %s", psc_desc(apply_config_rc));
322 }
323 else {
324 assert( new_argc == ntsa_length(new_argv) )((void) sizeof ((new_argc == ntsa_length(new_argv)) ? 1 : 0),
__extension__ ({ if (new_argc == ntsa_length(new_argv)) ; else
__assert_fail ("new_argc == ntsa_length(new_argv)", "api_base.c"
, 324, __extension__ __PRETTY_FUNCTION__); }))
;
325 if (debug)
326 ntsa_show(new_argv);
327
328 if (untokenized_option_string && strlen(untokenized_option_string) > 0) {
329 char * msg = g_strdup_printf("Using options from %s: %s",
330 config_fn, untokenized_option_string);
331 emit_parse_info_msg(msg, infomsgs);
332 free(msg);
333 }
334 }
335 g_ptr_array_free(errmsgs, true1);
336 free(config_fn);
337 }
338
339 if (!result) { // if no errors
340 assert(new_argc >= 1)((void) sizeof ((new_argc >= 1) ? 1 : 0), __extension__ ({
if (new_argc >= 1) ; else __assert_fail ("new_argc >= 1"
, "api_base.c", 340, __extension__ __PRETTY_FUNCTION__); }))
;
341 char * combined = strjoin((const char**)(new_argv+1), new_argc, " ");
342 char * msg = g_strdup_printf("Applying combined options: %s", combined);
343 emit_parse_info_msg(msg, infomsgs);
344 free(msg);
345
346 result = perform_parse(new_argc, new_argv, combined, parsed_cmd_loc);
347 ntsa_free(new_argv, true1);
348 free(combined);
349 free(untokenized_option_string);
350 }
351
352 DBGF(debug, "Done. *parsed_cmd_loc=%p. Returning %s",do { if (debug) simple_dbgmsg(debug, __func__, 353, "api_base.c"
, "Done. *parsed_cmd_loc=%p. Returning %s", *parsed_cmd_loc
, errinfo_summary(result)); } while(0)
353 *parsed_cmd_loc, errinfo_summary(result))do { if (debug) simple_dbgmsg(debug, __func__, 353, "api_base.c"
, "Done. *parsed_cmd_loc=%p. Returning %s", *parsed_cmd_loc
, errinfo_summary(result)); } while(0)
;
354
355 ASSERT_IFF(*parsed_cmd_loc, !result)((void) sizeof ((( (*parsed_cmd_loc) && (!result) ) ||
( !(*parsed_cmd_loc) && !(!result) )) ? 1 : 0), __extension__
({ if (( (*parsed_cmd_loc) && (!result) ) || ( !(*parsed_cmd_loc
) && !(!result) )) ; else __assert_fail ("( (*parsed_cmd_loc) && (!result) ) || ( !(*parsed_cmd_loc) && !(!result) )"
, "api_base.c", 355, __extension__ __PRETTY_FUNCTION__); }))
;
356 return result;
357}
358
359
360#ifdef TESTING_CLEANUP
361void done() {
362 printf("(%s) Starting\n", __func__);
363 _ddca_terminate();
364 SYSLOG(LOG_INFO6, "(%s) executing done()", __func__);
365 printf("(%s) Done.\n", __func__);
366}
367
368void dummy_sigterm_handler() {
369 printf("(%s) Executing. library_initialized = %s\n",
370 __func__, SBOOL(library_initialized)( (library_initialized) ? "true" : "false" ));
371}
372
373void atexit_func() {
374 printf("(%s) Executing. library_initalized = %s\n",
375 __func__, SBOOL(library_initialized)( (library_initialized) ? "true" : "false" ));
376}
377#endif
378
379
380
381/** Initializes the ddcutil library module.
382 *
383 * Called automatically when the shared library is loaded.
384 *
385 * Registers functions in RTTI table, performs additional initialization
386 * that cannot fail.
387 */
388void __attribute__ ((constructor))
389_ddca_new_init(void) {
390 bool_Bool debug = false0;
391 char * s = getenv("DDCUTIL_DEBUG_LIBINIT");
392 if (s && strlen(s) > 0)
393 debug = true1;
394
395 DBGF(debug, "Starting. library_initialized=%s\n", sbool(library_initialized))do { if (debug) simple_dbgmsg(debug, __func__, 395, "api_base.c"
, "Starting. library_initialized=%s\n", sbool(library_initialized
)); } while(0)
;
396
397 init_api_base(); // registers functions in RTTI table
398 init_base_services(); // initializes tracing related modules
399 init_ddc_services(); // initializes i2c, usb, ddc, vcp, dynvcp
400 init_api_services(); // other files in directory libmain
401
402#ifdef TESTING_CLEANUP
403 // int atexit_rc = atexit(done); // TESTING CLEANUP
404 // printf("(%s) atexit() returned %d\n", __func__, atexit_rc);
405#endif
406
407 DBGF(debug, "Done.")do { if (debug) simple_dbgmsg(debug, __func__, 407, "api_base.c"
, "Done."); } while(0)
;
408}
409
410
411//
412// Profiling
413//
414
415void profiling_enable(bool_Bool enabled) {
416 ptd_api_profiling_enabled = enabled;
417}
418
419void profiling_reset() {
420 ptd_profile_reset_all_stats();
421}
422
423void profile_start_call(void * func) {
424 ptd_profile_function_start(func);
425}
426
427void profile_end_call(void * func) {
428 ptd_profile_function_end(func);
429}
430
431void profile_report(FILE * dest, bool_Bool by_thread) {
432 if (dest) {
433 rpt_push_output_dest(dest);
434 }
435 ptd_profile_report_all_threads(0);
436 ptd_profile_report_stats_summary(0);
437 if (dest) {
438 rpt_pop_output_dest();
439 }
440}
441
442
443//
444// Tracing
445//
446
447void
448init_library_trace_file(char * library_trace_file, bool_Bool enable_syslog, bool_Bool debug) {
449 DBGF(debug, "library_trace_file = \"%s\", enable_syslog = %s", library_trace_file, sbool(enable_syslog))do { if (debug) simple_dbgmsg(debug, __func__, 449, "api_base.c"
, "library_trace_file = \"%s\", enable_syslog = %s", library_trace_file
, sbool(enable_syslog)); } while(0)
;
450 char * trace_file = (library_trace_file[0] != '/')
451 ? xdg_state_home_file("ddcutil", library_trace_file)
452 : g_strdup(library_trace_file)g_strdup_inline (library_trace_file);
453 DBGF(debug, "Setting trace destination %s", trace_file)do { if (debug) simple_dbgmsg(debug, __func__, 453, "api_base.c"
, "Setting trace destination %s", trace_file); } while(0)
;
454 SYSLOG2(DDCA_SYSLOG_NOTICE, "Trace destination: %s", trace_file)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE
); if (syslog_priority >= 0) { syslog(syslog_priority, "Trace destination: %s"
, trace_file); } } } while(0)
;
455
456 fopen_mkdir(trace_file, "a", stderrstderr, &flog);
457 if (flog) {
458 time_t trace_start_time = time(NULL((void*)0));
459 char * trace_start_time_s = asctime(localtime(&trace_start_time));
460 if (trace_start_time_s[strlen(trace_start_time_s)-1] == 0x0a)
461 trace_start_time_s[strlen(trace_start_time_s)-1] = 0;
462 fprintf(flog, "%s tracing started %s\n", "libddcutil", trace_start_time_s);
463 DBGF(debug, "Writing %s trace output to %s", "libddcutil",trace_file)do { if (debug) simple_dbgmsg(debug, __func__, 463, "api_base.c"
, "Writing %s trace output to %s", "libddcutil",trace_file); }
while(0)
;
464 set_default_thread_output_settings(flog, flog);
465 set_fout(flog);
466 set_ferr(flog);
467
468 rpt_set_default_output_dest(flog); // for future threads
469 rpt_push_output_dest(flog); // for this thread
470 }
471 else {
472 fprintf(stderrstderr, "Error opening libddcutil trace file %s: %s\n",
473 trace_file, strerror(errno(*__errno_location ())));
474 SYSLOG2(DDCA_SYSLOG_ERROR, "Error opening libddcutil trace file %s: %s",do { if (test_emit_syslog(DDCA_SYSLOG_ERROR)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_ERROR
); if (syslog_priority >= 0) { syslog(syslog_priority, "Error opening libddcutil trace file %s: %s"
, trace_file, strerror((*__errno_location ()))); } } } while(
0)
475 trace_file, strerror(errno))do { if (test_emit_syslog(DDCA_SYSLOG_ERROR)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_ERROR
); if (syslog_priority >= 0) { syslog(syslog_priority, "Error opening libddcutil trace file %s: %s"
, trace_file, strerror((*__errno_location ()))); } } } while(
0)
;
476 }
477 free(trace_file);
478 DBGF(debug, "Done.")do { if (debug) simple_dbgmsg(debug, __func__, 478, "api_base.c"
, "Done."); } while(0)
;
479}
480
481
482/** Cleanup at library termination
483 *
484 * - Terminates thread that watches for display addition or removal.
485 * - Releases heap memory to avoid error reports from memory analyzers.
486 */
487void __attribute__ ((destructor))
488_ddca_terminate(void) {
489 bool_Bool debug = false0;
490 DBGTRC_STARTING(debug, DDCA_TRC_API, "library_initialized = %s", SBOOL(library_initialized))dbgtrc( (debug || trace_callstack_call_depth > 0 || is_traced_callstack_call
(__func__) ) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x08, __func__,
490, "api_base.c", "Starting ""library_initialized = %s", (
(library_initialized) ? "true" : "false" ))
;
491 if (library_initialized) {
492 if (debug)
493 dbgrpt_display_locks(2);
494 if (dsa2_is_enabled())
495 dsa2_save_persistent_stats();
496 if (display_caching_enabled)
497 ddc_store_displays_cache();
498 ddc_discard_detected_displays();
499 if (requested_stats)
500 ddc_report_stats_main(requested_stats, per_display_stats, dsa_detail_stats, false0, 0);
501 ddc_stop_watch_displays(/*wait=*/ false0); // in case it was started
502 terminate_ddc_services();
503 terminate_base_services();
504 free_regex_hash_table();
505 library_initialized = false0;
506 if (flog)
507 fclose(flog);
508 DBGTRC_DONE(debug, DDCA_TRC_API, "library termination complete")dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL
: (DDCA_TRC_API), 0x10, __func__, 508, "api_base.c", "Done "
"library termination complete")
;
509 }
510 else {
511 DBGTRC_DONE(debug, DDCA_TRC_API, "library was already terminated")dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL
: (DDCA_TRC_API), 0x10, __func__, 511, "api_base.c", "Done "
"library was already terminated")
; // should be impossible
512 }
513 // special handling for termination msg
514 if (syslog_level > DDCA_SYSLOG_NEVER)
515 syslog(LOG_NOTICE5, "libddcutil terminating.");
516 if (syslog_level > DDCA_SYSLOG_NEVER && !client_opened_syslog)
517 closelog();
518}
519
520
521Error_Info *
522set_master_errinfo_from_init_errors(
523 GPtrArray * errs) // array of Error_Info *
524{
525 bool_Bool debug = false0;
526 DBGF(debug, "Starting. errs=%p", errs)do { if (debug) simple_dbgmsg(debug, __func__, 526, "api_base.c"
, "Starting. errs=%p", errs); } while(0)
;
527 Error_Info * master_error = NULL((void*)0);
528 if (errs && errs->len > 0) {
529 master_error = errinfo_new(DDCRC_BAD_DATA(-(3000 +27) ), __func__, "Invalid configuration options");
530 for (int ndx = 0; ndx < errs->len; ndx++) {
531 Error_Info * cur = g_ptr_array_index(errs, ndx)((errs)->pdata)[ndx];
532 errinfo_add_cause(master_error, cur);
533 }
534 g_ptr_array_free(errs, false0);
535 }
536 DBGF(debug, "Done. Returning %p")do { if (debug) simple_dbgmsg(debug, __func__, 536, "api_base.c"
, "Done. Returning %p"); } while(0)
;
537 return master_error;
538}
539
540
541DDCA_Status
542set_ddca_error_detail_from_init_errors(
543 GPtrArray * errs) // array of Error_Info *
544{
545 bool_Bool debug = false0;
546 DDCA_Status ddcrc = 0;
547 if (errs && errs->len > 0) {
548 Error_Info * master_error = errinfo_new(DDCRC_BAD_DATA(-(3000 +27) ), __func__, "Invalid configuration options");
549 ddcrc = DDCRC_BAD_DATA(-(3000 +27) );
550 for (int ndx = 0; ndx < errs->len; ndx++) {
551 Error_Info * cur = g_ptr_array_index(errs, ndx)((errs)->pdata)[ndx];
552 errinfo_add_cause(master_error, cur);
553 }
554 DDCA_Error_Detail * public_error_detail = error_info_to_ddca_detail(master_error);
555 errinfo_free_with_report(master_error, debug, __func__);
556 save_thread_error_detail(public_error_detail);
557 }
558 // clear if no errors?
559 return ddcrc;
560}
561
562
563DDCA_Syslog_Level ddca_syslog_level_from_name(const char * name) {
564 return syslog_level_name_to_value(name);
565}
566
567
568void report_parse_errors0(Error_Info * erec, int depth, int max_depth) {
569 char * edesc = psc_text(erec->status_code);
570
571 if (depth == 0) {
572 rpt_vstring(depth, "%s: %s", edesc, erec->detail);
573 }
574 else {
575 rpt_vstring(depth, "%s", erec->detail);
576 }
577 if (depth < max_depth) {
578 if (erec->cause_ct > 0) {
579 for (int ndx = 0; ndx < erec->cause_ct; ndx++) {
580 Error_Info * cur = erec->causes[ndx];
581 report_parse_errors0(cur, depth+1, max_depth);
582 }
583 }
584 }
585}
586
587
588void report_parse_errors(Error_Info * erec) {
589 if (erec) {
590 rpt_push_output_dest(ferr());
591 report_parse_errors0(erec, 0, 3);
592 rpt_pop_output_dest();
593 }
594}
595
596
597DDCA_Status
598ddci_init(const char * libopts,
599 DDCA_Syslog_Level syslog_level_arg,
600 DDCA_Init_Options opts,
601 char*** infomsg_loc)
602{
603 bool_Bool debug = false0;
604 char * s = getenv("DDCUTIL_DEBUG_LIBINIT");
5
Assuming the environment variable exists
605 if (s
5.1
's' is non-null
&& strlen(s) > 0)
6
Assuming the condition is true
7
Taking true branch
606 debug = true1;
607
608 DBGF(debug, "Starting. library_initialized=%s", sbool(library_initialized))do { if (debug) simple_dbgmsg(debug, __func__, 608, "api_base.c"
, "Starting. library_initialized=%s", sbool(library_initialized
)); } while(0)
;
8
Taking true branch
9
Loop condition is false. Exiting loop
609
610 if (infomsg_loc
9.1
'infomsg_loc' is null
)
10
Taking false branch
611 *infomsg_loc = NULL((void*)0);
612
613 Parsed_Cmd * parsed_cmd = NULL((void*)0);
11
'parsed_cmd' initialized to a null pointer value
614 Error_Info * master_error = NULL((void*)0);
615 if (library_initialized) {
12
Assuming 'library_initialized' is true
13
Taking true branch
616 master_error = ERRINFO_NEW(DDCRC_INVALID_OPERATION, "libddcutil already initialized")errinfo_new((-(3000 +14) ), __func__, "libddcutil already initialized"
)
;
617 SYSLOG2(DDCA_SYSLOG_ERROR, "libddcutil already initialized")do { if (test_emit_syslog(DDCA_SYSLOG_ERROR)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_ERROR
); if (syslog_priority >= 0) { syslog(syslog_priority, "libddcutil already initialized"
); } } } while(0)
;
14
Assuming the condition is false
15
Taking false branch
16
Loop condition is false. Exiting loop
618 }
619 else {
620 enable_init_msgs = opts & DDCA_INIT_OPTIONS_ENABLE_INIT_MSGS;
621 // enable_init_msgs = true; // *** TEMP ***
622 client_opened_syslog = opts & DDCA_INIT_OPTIONS_CLIENT_OPENED_SYSLOG;
623 if (syslog_level_arg == DDCA_SYSLOG_NOT_SET)
624 syslog_level_arg = DEFAULT_LIBDDCUTIL_SYSLOG_LEVELDDCA_SYSLOG_NOTICE;
625 if (syslog_level_arg != DDCA_SYSLOG_NEVER) {
626 enable_syslog = true1;
627 if (!client_opened_syslog) {
628 openlog("libddcutil", // prepended to every log message
629 LOG_CONS0x02 | LOG_PID0x01, // write to system console if error sending to system logger
630 // include caller's process id
631 LOG_USER(1<<3)); // generic user program, syslogger can use to determine how to handle
632 }
633 // special handling for start and termination msgs
634 // always output if syslog is opened
635 syslog(LOG_NOTICE5, "Initializing libddcutil. ddcutil version: %s, shared library: %s",
636 get_full_ddcutil_version(), ddca_libddcutil_filename());
637 }
638 syslog_level = syslog_level_arg; // global in trace_control.h
639
640 GPtrArray* infomsgs = NULL((void*)0);
641 infomsgs = g_ptr_array_new_with_free_func(g_free);
642
643 if ((opts & DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE) && !libopts) {
644 parsed_cmd = new_parsed_cmd();
645 }
646 else {
647 master_error = get_parsed_libmain_config(
648 libopts,
649 opts & DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE,
650 infomsgs,
651 &parsed_cmd);
652 ASSERT_IFF(master_error, !parsed_cmd)((void) sizeof ((( (master_error) && (!parsed_cmd) ) ||
( !(master_error) && !(!parsed_cmd) )) ? 1 : 0), __extension__
({ if (( (master_error) && (!parsed_cmd) ) || ( !(master_error
) && !(!parsed_cmd) )) ; else __assert_fail ("( (master_error) && (!parsed_cmd) ) || ( !(master_error) && !(!parsed_cmd) )"
, "api_base.c", 652, __extension__ __PRETTY_FUNCTION__); }))
;
653
654 if (enable_init_msgs && infomsgs && infomsgs->len > 0) {
655 for (int ndx = 0; ndx < infomsgs->len; ndx++)
656 fprintf(fout(), "%s\n", (char*) g_ptr_array_index(infomsgs, ndx)((infomsgs)->pdata)[ndx]);
657 }
658 if (infomsg_loc) {
659 *infomsg_loc = g_ptr_array_to_ntsa(infomsgs, /*duplicate=*/true1);
660 }
661 g_ptr_array_free(infomsgs, true1);
662
663 if (!master_error) {
664 if (parsed_cmd->trace_destination) {
665 DBGF(debug, "Setting library trace file: %s", parsed_cmd->trace_destination)do { if (debug) simple_dbgmsg(debug, __func__, 665, "api_base.c"
, "Setting library trace file: %s", parsed_cmd->trace_destination
); } while(0)
;
666 init_library_trace_file(parsed_cmd->trace_destination, enable_syslog, debug);
667 }
668 master_error = init_tracing(parsed_cmd);
669 requested_stats = parsed_cmd->stats_types;
670 ptd_api_profiling_enabled = parsed_cmd->flags & CMD_FLAG_PROFILE_API;
671 per_display_stats = parsed_cmd->flags & CMD_FLAG_VERBOSE_STATS;
672 dsa_detail_stats = parsed_cmd->flags & CMD_FLAG_INTERNAL_STATS;
673 if (!submaster_initializer(parsed_cmd))
674 master_error = ERRINFO_NEW(DDCRC_UNINITIALIZED, "Initialization failed")errinfo_new((-(3000 +16) ), __func__, "Initialization failed"
)
;
675 }
676 }
677 }
678
679 DDCA_Status ddcrc = 0;
680 if (master_error) {
17
Assuming 'master_error' is null
18
Taking false branch
681 ddcrc = master_error->status_code;
682 DDCA_Error_Detail * public_error_detail = error_info_to_ddca_detail(master_error);
683 save_thread_error_detail(public_error_detail);
684 if (test_emit_syslog(DDCA_SYSLOG_ERROR)) {
685 SYSLOG2(DDCA_SYSLOG_ERROR, "Library initialization failed: %s", psc_desc(master_error->status_code))do { if (test_emit_syslog(DDCA_SYSLOG_ERROR)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_ERROR
); if (syslog_priority >= 0) { syslog(syslog_priority, "Library initialization failed: %s"
, psc_desc(master_error->status_code)); } } } while(0)
;
686 for (int ndx = 0; ndx < master_error->cause_ct; ndx++) {
687 SYSLOG2(DDCA_SYSLOG_ERROR, "%s", master_error->causes[ndx]->detail)do { if (test_emit_syslog(DDCA_SYSLOG_ERROR)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_ERROR
); if (syslog_priority >= 0) { syslog(syslog_priority, "%s"
, master_error->causes[ndx]->detail); } } } while(0)
;
688 }
689 }
690 if (enable_init_msgs) {
691 printf("(%s) calling report_parse_errors()\n", __func__);
692 report_parse_errors(master_error);
693 }
694 errinfo_free(master_error);
695 library_initialization_failed = true1;
696 }
697 else {
698 i2c_detect_buses();
699 ddc_ensure_displays_detected();
700 if (parsed_cmd->flags&CMD_FLAG_WATCH_DISPLAY_HOTPLUG_EVENTS)
19
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'parsed_cmd')
701 ddc_start_watch_displays();
702 library_initialized = true1;
703 library_initialization_failed = false0;
704 SYSLOG2(DDCA_SYSLOG_NOTICE, "Library initialization complete.")do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority
= syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE
); if (syslog_priority >= 0) { syslog(syslog_priority, "Library initialization complete."
); } } } while(0)
;
705 }
706 free_parsed_cmd(parsed_cmd);
707
708 DBGF(debug, "Done. Returning: %s", psc_desc(ddcrc))do { if (debug) simple_dbgmsg(debug, __func__, 708, "api_base.c"
, "Done. Returning: %s", psc_desc(ddcrc)); } while(0)
;
709
710 return ddcrc;
711}
712
713
714DDCA_Status
715ddca_init(const char * libopts,
716 DDCA_Syslog_Level syslog_level_arg,
717 DDCA_Init_Options opts)
718{
719 return ddci_init(libopts, syslog_level_arg, opts, NULL((void*)0));
4
Calling 'ddci_init'
720}
721
722DDCA_Status
723ddca_init2(const char * libopts,
724 DDCA_Syslog_Level syslog_level_arg,
725 DDCA_Init_Options opts,
726 char*** infomsg_loc
727 )
728{
729 return ddci_init(libopts, syslog_level_arg, opts, infomsg_loc);
730}
731
732
733
734DDCA_Status
735ddca_start_watch_displays() {
736 bool_Bool debug = false0;
737 API_PROLOG(debug, "Starting")do { if (!library_initialized) { ddca_init(((void*)0), DDCA_SYSLOG_NOTICE
, DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE); } if (trace_api_call_depth
> 0 || is_traced_api_call(__func__) ) trace_api_call_depth
++; dbgtrc( (debug) ? DDCA_TRC_ALL : DDCA_TRC_API, 0x00, __func__
, 737, "api_base.c", "Starting ""Starting"); if (ptd_api_profiling_enabled
) ptd_profile_function_start(__func__); } while(0)
;
738 ddc_start_watch_displays(false0);
739 API_EPILOG(debug, DDCRC_OK, "")do { dbgtrc_ret_ddcrc( (debug) ? DDCA_TRC_ALL : DDCA_TRC_API,
0x00, __func__, 739, "api_base.c", 0, ""); if (trace_api_call_depth
> 0) trace_api_call_depth--; if (ptd_api_profiling_enabled
) ptd_profile_function_end(__func__); return 0; } while(0)
;
740}
741
742
743
744DDCA_Status
745ddca_stop_watch_displays(bool_Bool wait) {
746 bool_Bool debug = false0;
747 API_PROLOG(debug, "Starting")do { if (!library_initialized) { ddca_init(((void*)0), DDCA_SYSLOG_NOTICE
, DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE); } if (trace_api_call_depth
> 0 || is_traced_api_call(__func__) ) trace_api_call_depth
++; dbgtrc( (debug) ? DDCA_TRC_ALL : DDCA_TRC_API, 0x00, __func__
, 747, "api_base.c", "Starting ""Starting"); if (ptd_api_profiling_enabled
) ptd_profile_function_start(__func__); } while(0)
;
1
Assuming 'library_initialized' is false
2
Taking true branch
3
Calling 'ddca_init'
748 ddc_stop_watch_displays(wait);
749 API_EPILOG(debug, DDCRC_OK, "")do { dbgtrc_ret_ddcrc( (debug) ? DDCA_TRC_ALL : DDCA_TRC_API,
0x00, __func__, 749, "api_base.c", 0, ""); if (trace_api_call_depth
> 0) trace_api_call_depth--; if (ptd_api_profiling_enabled
) ptd_profile_function_end(__func__); return 0; } while(0)
;
750}
751
752
753//
754// Error Detail
755//
756
757DDCA_Error_Detail *
758ddca_get_error_detail() {
759 bool_Bool debug = false0;
760 DBGMSF(debug, "Starting")do { if (debug) dbgtrc(DDCA_TRC_ALL, 0x00, __func__, 760, "api_base.c"
, "Starting"); } while(0)
;
761
762 DDCA_Error_Detail * result = dup_error_detail(get_thread_error_detail());
763
764 if (debug) {
765 DBGMSG("Done. Returning: %p", result)dbgtrc(DDCA_TRC_ALL, 0x00, __func__, 765, "api_base.c", "Done. Returning: %p"
, result)
;
766 if (result)
767 report_error_detail(result, 2);
768 }
769 return result;
770}
771
772
773void
774ddca_free_error_detail(DDCA_Error_Detail * ddca_erec) {
775 free_error_detail(ddca_erec);
776}
777
778
779void
780ddca_report_error_detail(DDCA_Error_Detail * ddca_erec, int depth) {
781 report_error_detail(ddca_erec, depth);
782}
783
784
785// DDCA_Error_Detail * ddca_dup_error_detail(DDCA_Error_Detail * original) {
786// return dup_error_detail(original);
787// }
788
789
790//
791// Status Code Management
792//
793
794const char *
795ddca_rc_name(DDCA_Status status_code) {
796 char * result = NULL((void*)0);
797 Status_Code_Info * code_info = find_status_code_info(status_code);
798 if (code_info)
799 result = code_info->name;
800 return result;
801}
802
803
804const char *
805ddca_rc_desc(DDCA_Status status_code) {
806 char * result = "unknown status code";
807 Status_Code_Info * code_info = find_status_code_info(status_code);
808 if (code_info)
809 result = code_info->description;
810 return result;
811}
812
813
814//
815// Output redirection
816//
817
818// Redirects output that normally would go to STDOUT
819void
820ddca_set_fout(FILE * fout) {
821 // DBGMSG("Starting. fout=%p", fout);
822 set_fout(fout);
823}
824
825
826void
827ddca_set_fout_to_default(void) {
828 set_fout_to_default();
829}
830
831
832// Redirects output that normally would go to STDERR
833void
834ddca_set_ferr(FILE * ferr) {
835 set_ferr(ferr);
836}
837
838
839void
840ddca_set_ferr_to_default(void) {
841 set_ferr_to_default();
842}
843
844
845//
846// Output capture - convenience functions
847//
848
849void
850ddca_start_capture(DDCA_Capture_Option_Flags flags) {
851 start_capture(flags);
852}
853
854
855char *
856ddca_end_capture(void) {
857 return end_capture();
858}
859
860
861
862//
863// Message Control
864//
865
866DDCA_Output_Level
867ddca_get_output_level(void) {
868 return get_output_level();
869}
870
871
872DDCA_Output_Level
873ddca_set_output_level(DDCA_Output_Level newval) {
874 return set_output_level(newval);
875}
876
877
878char *
879ddca_output_level_name(DDCA_Output_Level val) {
880 return output_level_name(val);
881}
882
883
884//
885// Global Settings
886//
887
888#ifdef REMOVED
889int
890ddca_max_max_tries(void) {
891 return MAX_MAX_TRIES15;
892}
893
894
895// *** THIS IS FOR THE CURRENT THREAD
896// *** replace using function specifying display
897// *** for now, revert to old try_data_get_maxtries2()
898int
899ddca_get_max_tries(DDCA_Retry_Type retry_type) {
900 // stats for multi part writes and reads are separate, but the
901 // max tries for both are identical
902// #ifndef NDEBUG
903 Retry_Op_Value result3 = try_data_get_maxtries2((Retry_Operation) retry_type);
904// #endif
905 // // new way using retry_mgt
906 // Retry_Op_Value result2 = trd_get_thread_max_tries((Retry_Operation) retry_type);
907 // assert(result == result2);
908 // assert(result2 == result3);
909 return result3;
910}
911
912
913// ** THIS IS FOR CURRENT THREAD - FIX
914DDCA_Status
915ddca_set_max_tries(
916 DDCA_Retry_Type retry_type,
917 int max_tries)
918{
919 DDCA_Status rc = 0;
920 free_thread_error_detail();
921 if (max_tries < 1 || max_tries > MAX_MAX_TRIES15)
922 rc = DDCRC_ARG(-(3000 +13) );
923 else {
924 try_data_set_maxtries2((Retry_Operation) retry_type, max_tries);
925 // for DDCA_MULTI_PART_TRIES, set both MULTI_PART_WRITE_OP and MULTI_PART_READ_OP
926 if (retry_type == DDCA_MULTI_PART_TRIES)
927 try_data_set_maxtries2(MULTI_PART_WRITE_OP, max_tries);
928
929 // new way, set in retry_mgt
930#ifdef TRD
931 trd_set_thread_max_tries((Retry_Operation) retry_type, max_tries);
932 if (retry_type == DDCA_MULTI_PART_TRIES)
933 trd_set_thread_max_tries(MULTI_PART_WRITE_OP, max_tries);
934#endif
935 }
936 return rc;
937}
938#endif
939
940bool_Bool
941ddca_enable_verify(bool_Bool onoff) {
942 return ddc_set_verify_setvcp(onoff);
943}
944
945
946bool_Bool
947ddca_is_verify_enabled() {
948 return ddc_get_verify_setvcp();
949}
950
951
952#ifdef REMOVED
953
954// *** FOR CURRENT THREAD
955double
956ddca_set_default_sleep_multiplier(double multiplier)
957{
958 bool_Bool debug = false0;
959 DBGTRC_STARTING(debug, DDCA_TRC_API, "Setting multiplier = %6.3f", multiplier)dbgtrc( (debug || trace_callstack_call_depth > 0 || is_traced_callstack_call
(__func__) ) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x08, __func__,
959, "api_base.c", "Starting ""Setting multiplier = %6.3f",
multiplier)
;
960
961 double old_value = -1.0;
962 if (multiplier >= 0.0 && multiplier <= 10.0) {
963// #ifdef TSD
964 old_value = pdd_get_default_sleep_multiplier_factor();
965 pdd_set_default_sleep_multiplier_factor(multiplier, Reset);
966// #endif
967 }
968
969 DBGTRC_DONE(debug, DDCA_TRC_API, "Returning: %6.3f", old_value)dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL
: (DDCA_TRC_API), 0x10, __func__, 969, "api_base.c", "Done "
"Returning: %6.3f", old_value)
;
970 return old_value;
971}
972
973
974double
975ddca_get_default_sleep_multiplier()
976{
977 bool_Bool debug = false0;
978 DBGTRC_STARTING(debug, DDCA_TRC_API, "")dbgtrc( (debug || trace_callstack_call_depth > 0 || is_traced_callstack_call
(__func__) ) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x08, __func__,
978, "api_base.c", "Starting """)
;
979 double result = pdd_get_default_sleep_multiplier_factor();
980 DBGTRC(debug, DDCA_TRC_API, "Returning %6.3f", result)dbgtrc( (debug) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x00, __func__
, 980, "api_base.c", "Returning %6.3f", result)
;
981 return result;
982}
983
984
985void
986ddca_set_global_sleep_multiplier(double multiplier)
987{
988 ddca_set_default_sleep_multiplier(multiplier);
989 return;
990}
991
992double
993ddca_get_global_sleep_multiplier()
994{
995 return ddca_get_default_sleep_multiplier();
996}
997#endif
998
999
1000double
1001ddca_set_sleep_multiplier(double multiplier)
1002{
1003 bool_Bool debug = false0;
1004 DBGTRC_STARTING(debug, DDCA_TRC_API, "Setting multiplier = %6.3f", multiplier)dbgtrc( (debug || trace_callstack_call_depth > 0 || is_traced_callstack_call
(__func__) ) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x08, __func__,
1004, "api_base.c", "Starting ""Setting multiplier = %6.3f"
, multiplier)
;
1005
1006 double old_value = -1.0;
1007 if (multiplier >= 0.0 && multiplier <= 10.0) {
1008 Per_Thread_Data * ptd = ptd_get_per_thread_data();
1009 old_value = ptd->sleep_multiplier;
1010 ptd->sleep_multiplier = multiplier;
1011 }
1012
1013 DBGTRC_DONE(debug, DDCA_TRC_API, "Returning: %6.3f", old_value)dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL
: (DDCA_TRC_API), 0x10, __func__, 1013, "api_base.c", "Done "
"Returning: %6.3f", old_value)
;
1014 return old_value;
1015}
1016
1017double
1018ddca_get_sleep_multiplier()
1019{
1020 bool_Bool debug = false0;
1021 DBGTRC(debug, DDCA_TRC_API, "")dbgtrc( (debug) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x00, __func__
, 1021, "api_base.c", "")
;
1022
1023 Per_Thread_Data * ptd = ptd_get_per_thread_data();
1024 double result = ptd->sleep_multiplier;
1025
1026 DBGTRC(debug, DDCA_TRC_API, "Returning %6.3f", result)dbgtrc( (debug) ? DDCA_TRC_ALL : (DDCA_TRC_API), 0x00, __func__
, 1026, "api_base.c", "Returning %6.3f", result)
;
1027 return result;
1028}
1029
1030
1031#ifdef FUTURE
1032
1033/** Gets the I2C timeout in milliseconds for the specified timeout class.
1034 * @param timeout_type timeout type
1035 * @return timeout in milliseconds
1036 */
1037int
1038ddca_get_timeout_millis(
1039 DDCA_Timeout_Type timeout_type) {
1040 return 0; // *** UNIMPLEMENTED ***
1041}
1042
1043/** Sets the I2C timeout in milliseconds for the specified timeout class
1044 * @param timeout_type timeout class
1045 * @param millisec timeout to set, in milliseconds
1046 */
1047void
1048ddca_set_timeout_millis(
1049 DDCA_Timeout_Type timeout_type,
1050 int millisec)
1051{
1052 // *** UNIMPLEMENTED
1053}
1054#endif
1055
1056
1057#ifdef REMOVED
1058
1059/** Controls the force I2C slave address setting.
1060 *
1061 * Normally, ioctl operation I2C_SLAVE is used to set the I2C slave address.
1062 * If that returns EBUSY and this setting is in effect, slave address setting
1063 * is retried using operation I2C_SLAVE_FORCE.
1064 *
1065 * @param[in] onoff true/false
1066 * @return prior value
1067 * @since 1.2.2
1068 */
1069bool_Bool
1070ddca_enable_force_slave_address(bool_Bool onoff);
1071
1072/** Query the force I2C slave address setting.
1073 *
1074 * @return true/false
1075 * @since 1.2.2
1076 */
1077bool_Bool
1078ddca_is_force_slave_address_enabled(void);
1079#endif
1080
1081#ifdef REMOVED
1082bool_Bool
1083ddca_enable_force_slave_address(bool_Bool onoff) {
1084 bool_Bool old = i2c_forceable_slave_addr_flag;
1085 i2c_forceable_slave_addr_flag = onoff;
1086 return old;
1087}
1088
1089
1090bool_Bool
1091ddca_is_force_slave_address_enabled(void) {
1092 return i2c_forceable_slave_addr_flag;
1093}
1094#endif
1095
1096
1097//
1098// Statistics
1099//
1100
1101// TODO: Add functions to access ddcutil's runtime error statistics
1102
1103void
1104ddca_reset_stats(void) {
1105 // DBGMSG("Executing");
1106 ddc_reset_stats_main();
1107}
1108
1109// TODO: Functions that return stats in data structures
1110void
1111ddca_show_stats(
1112 DDCA_Stats_Type stats_types,
1113 bool_Bool per_display_stats,
1114 int depth)
1115{
1116 if (stats_types)
1117 ddc_report_stats_main( stats_types, per_display_stats, per_display_stats, false0, depth);
1118}
1119
1120void
1121ddca_report_locks(
1122 int depth)
1123{
1124 dbgrpt_display_locks(depth);
1125}
1126
1127
1128void init_api_base() {
1129 // DBGMSG("Executing");
1130 RTTI_ADD_FUNC(_ddca_terminate)rtti_func_name_table_add(_ddca_terminate, "_ddca_terminate");;
1131 RTTI_ADD_FUNC(ddca_start_watch_displays)rtti_func_name_table_add(ddca_start_watch_displays, "ddca_start_watch_displays"
);
;
1132 RTTI_ADD_FUNC(ddca_stop_watch_displays)rtti_func_name_table_add(ddca_stop_watch_displays, "ddca_stop_watch_displays"
);
;
1133#ifdef REMOVED
1134 RTTI_ADD_FUNC(ddca_set_sleep_multiplier)rtti_func_name_table_add(ddca_set_sleep_multiplier, "ddca_set_sleep_multiplier"
);
;
1135 RTTI_ADD_FUNC(ddca_set_default_sleep_multiplier)rtti_func_name_table_add(ddca_set_default_sleep_multiplier, "ddca_set_default_sleep_multiplier"
);
;
1136#endif
1137}
1138