diff --git a/client/client_state.h b/client/client_state.h index c1bbb2b9e91..b43131cb010 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2022 University of California +// Copyright (C) 2023 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -128,7 +128,7 @@ struct CLIENT_STATE { // - (Mac) client was started from screensaver, // which has since exited bool os_requested_suspend; - // we should suspend for OS reasonts (used on Win only). + // we should suspend for OS reasons (used on Win only). // Set when // - got BATTERY_LOW, SUSPEND, SERVICE_CONTROL_PAUSE double os_requested_suspend_time; @@ -431,6 +431,7 @@ struct CLIENT_STATE { const char* fname = GLOBAL_PREFS_FILE_NAME, const char* override_fname = GLOBAL_PREFS_OVERRIDE_FILE ); + void validate_global_prefs(const GLOBAL_PREFS_MASK& mask); void print_global_prefs(); int save_global_prefs(const char* prefs, char* url, char* sched); double available_ram(); diff --git a/client/cs_prefs.cpp b/client/cs_prefs.cpp index d73e497aa69..be9363a5c07 100644 --- a/client/cs_prefs.cpp +++ b/client/cs_prefs.cpp @@ -661,6 +661,7 @@ void CLIENT_STATE::read_global_prefs( msg_printf(NULL, MSG_INFO, "Reading preferences override file"); fclose(f); global_prefs.override_file_present = true; + validate_global_prefs(mask); } } @@ -684,6 +685,279 @@ void CLIENT_STATE::read_global_prefs( #endif } +// Validates preferences that were parsed. Uses the mask structure, so +// this should be called immediately after parsing. This function will check if +// any preferences are out of a reasonable range for each variable. This could be +// any of the following: +// 1. A negative number. +// 2. Maximum limits. +// 3. Checking to make sure a percentage is between 0% and 100%. +// 4. A time variable that is out of range. +// If the variable is out of range, it will either be set to the default value, 0, +// 0%, 100%, 0:00, or 24:00, depending on the variable. Default values are derived +// from GLOBAL_PREFS::defaults(). +// Any new preference variables added should be validated here as well. +// +void CLIENT_STATE::validate_global_prefs(const GLOBAL_PREFS_MASK& mask) { + // ubound is an upper limit for doubles as a sanity check. This matches + // the upper limit as preferences are validated from the Manager. Refer to + // CDlgAdvPreferences::ValidateInput as an example. + // + double const ubound = 9999999999999.99; + char* outrange = "is out of range. Setting changed to"; + char* timechange = "is not a valid time. Setting changed to"; + char* forday = "for day"; + if (mask.battery_charge_min_pct) { + if (global_prefs.battery_charge_min_pct < 0) { + global_prefs.battery_charge_min_pct = 90; + msg_printf(0, MSG_USER_ALERT, "'battery_charge_min_pct' %s 90.", outrange); + } else if (global_prefs.battery_charge_min_pct > 100) { + global_prefs.battery_charge_min_pct = 100; + msg_printf(0, MSG_USER_ALERT, "'battery_charge_min_pct' %s 100.", outrange); + } + } + if (mask.battery_max_temperature) { + if (global_prefs.battery_max_temperature < -273.15 || global_prefs.battery_max_temperature > ubound) { + global_prefs.battery_max_temperature = 40; + msg_printf(0, MSG_USER_ALERT, "'battery_max_temperature' %s 40.", outrange); + } + } + if (mask.idle_time_to_run) { + if (global_prefs.idle_time_to_run < 0 || global_prefs.idle_time_to_run > ubound) { + global_prefs.idle_time_to_run = 3; + msg_printf(0, MSG_USER_ALERT, "'idle_time_to_run' %s 3.", outrange); + } + } + if (mask.suspend_if_no_recent_input) { + if (global_prefs.suspend_if_no_recent_input < 0 || global_prefs.suspend_if_no_recent_input > ubound) { + global_prefs.suspend_if_no_recent_input = 0; + msg_printf(0, MSG_USER_ALERT, "'suspend_if_no_recent_input' %s 0.", outrange); + } + } + if (mask.suspend_cpu_usage) { + if (global_prefs.suspend_cpu_usage < 0) { + global_prefs.suspend_cpu_usage = 25; + msg_printf(0, MSG_USER_ALERT, "'suspend_cpu_usage' %s 25.", outrange); + } else if (global_prefs.suspend_cpu_usage > 100) { + global_prefs.suspend_cpu_usage = 100; + msg_printf(0, MSG_USER_ALERT, "'suspend_cpu_usage' %s 100.", outrange); + } + } + if (mask.niu_suspend_cpu_usage) { + if (global_prefs.niu_suspend_cpu_usage < 0) { + global_prefs.niu_suspend_cpu_usage = 50; + msg_printf(0, MSG_USER_ALERT, "'niu_suspend_cpu_usage' %s 50.", outrange); + } else if (global_prefs.niu_suspend_cpu_usage > 100) { + global_prefs.niu_suspend_cpu_usage = 100; + msg_printf(0, MSG_USER_ALERT, "'niu_suspend_cpu_usage' %s 100.", outrange); + } + } + if (mask.start_hour) { + if (global_prefs.cpu_times.start_hour < 0) { + global_prefs.cpu_times.start_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'start_hour' %s 0:00.", timechange); + } else if (global_prefs.cpu_times.start_hour > 24) { + global_prefs.cpu_times.start_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'start_hour' %s 24:00.", timechange); + } + } + if (mask.end_hour) { + if (global_prefs.cpu_times.end_hour < 0) { + global_prefs.cpu_times.end_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'end_hour' %s 0:00.", timechange); + } else if (global_prefs.cpu_times.end_hour > 24) { + global_prefs.cpu_times.end_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'end_hour' %s 24:00.", timechange); + } + } + if (mask.net_start_hour) { + if (global_prefs.net_times.start_hour < 0) { + global_prefs.net_times.start_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'net_start_hour' %s 0:00.", timechange); + } else if (global_prefs.net_times.start_hour > 24) { + global_prefs.net_times.start_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'net_start_hour' %s 24:00.", timechange); + } + } + if (mask.net_end_hour) { + if (global_prefs.net_times.end_hour < 0) { + global_prefs.net_times.end_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'net_end_hour' %s 0:00.", timechange); + } else if (global_prefs.net_times.end_hour > 24) { + global_prefs.net_times.end_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'net_end_hour' %s 24:00.", timechange); + } + } + // Validate day-of-week override preferences, if set. + for (int i = 0; i < 7; i++) { + if (global_prefs.cpu_times.week.days[i].present) { + if (global_prefs.cpu_times.week.days[i].start_hour < 0) { + global_prefs.cpu_times.week.days[i].start_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'start_hour' %s %d %s 0:00", forday, i, timechange); + } else if (global_prefs.cpu_times.week.days[i].start_hour > 24) { + global_prefs.cpu_times.week.days[i].start_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'start_hour' %s %d %s 24:00", forday, i, timechange); + } + if (global_prefs.cpu_times.week.days[i].end_hour < 0) { + global_prefs.cpu_times.week.days[i].end_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'end_hour' %s %d %s 0:00", forday, i, timechange); + } else if (global_prefs.cpu_times.week.days[i].end_hour > 24) { + global_prefs.cpu_times.week.days[i].end_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'end_hour' %s %d %s 24:00", forday, i, timechange); + } + } + if (global_prefs.net_times.week.days[i].present) { + if (global_prefs.net_times.week.days[i].start_hour < 0) { + global_prefs.net_times.week.days[i].start_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'net_start_hour' %s %d %s 0:00", forday, i, timechange); + } else if (global_prefs.net_times.week.days[i].start_hour > 24) { + global_prefs.net_times.week.days[i].start_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'net_start_hour' %s %d %s 24:00", forday, i, timechange); + } + if (global_prefs.net_times.week.days[i].end_hour < 0) { + global_prefs.net_times.week.days[i].end_hour = 0; + msg_printf(0, MSG_USER_ALERT, "'net_end_hour' %s %d %s 00:00", forday, i, timechange); + } else if (global_prefs.net_times.week.days[i].end_hour > 24) { + global_prefs.net_times.week.days[i].end_hour = 24; + msg_printf(0, MSG_USER_ALERT, "'net_end_hour' %s %d %s 24:00", forday, i, timechange); + } + } + } + if (mask.work_buf_min_days) { + if (global_prefs.work_buf_min_days < 0 || global_prefs.work_buf_min_days > 10) { + global_prefs.work_buf_min_days = 0.1; + msg_printf(0, MSG_USER_ALERT, "'work_buf_min_days' %s 0.1.", outrange); + } + } + if (mask.work_buf_additional_days) { + if (global_prefs.work_buf_additional_days < 0 || global_prefs.work_buf_additional_days > 10) { + global_prefs.work_buf_additional_days = 0.5; + msg_printf(0, MSG_USER_ALERT, "'work_buf_additional_days' %s 0.5.", outrange); + } + } + if (mask.max_ncpus_pct) { + if (global_prefs.max_ncpus_pct < 0) { +#ifdef ANDROID + global_prefs.max_ncpus_pct = 50; + msg_printf(0, MSG_USER_ALERT, "'max_ncpus_pct' %s 50.", outrange); +#else + global_prefs.max_ncpus_pct = 0; + msg_printf(0, MSG_USER_ALERT, "'max_ncpus_pct' %s 0.", outrange); +#endif + } else if (global_prefs.max_ncpus_pct > 100) { + global_prefs.max_ncpus_pct = 100; + msg_printf(0, MSG_USER_ALERT, "'max_ncpus_pct' %s 100.", outrange); + } + } + if (mask.niu_max_ncpus_pct) { + if (global_prefs.niu_max_ncpus_pct < 0) { + global_prefs.niu_max_ncpus_pct = 0; + msg_printf(0, MSG_USER_ALERT, "'niu_max_ncpus_pct' %s 0.", outrange); + } else if (global_prefs.niu_max_ncpus_pct > 100) { + global_prefs.niu_max_ncpus_pct = 100; + msg_printf(0, MSG_USER_ALERT, "'niu_max_ncpus_pct' %s 100.", outrange); + } + } + if (mask.max_ncpus) { + if (global_prefs.max_ncpus < 0 || global_prefs.max_ncpus > ubound) { + global_prefs.max_ncpus = 0; + msg_printf(0, MSG_USER_ALERT, "'max_ncpus' %s 0.", outrange); + } + } + if (mask.disk_interval) { + if (global_prefs.disk_interval < 0 || global_prefs.disk_interval > ubound) { + global_prefs.disk_interval = 60; + msg_printf(0, MSG_USER_ALERT, "'disk_interval' %s 60.", outrange); + } + } + if (mask.cpu_scheduling_period_minutes) { + if (global_prefs.cpu_scheduling_period_minutes < 0.0001 || global_prefs.cpu_scheduling_period_minutes > ubound) { + global_prefs.cpu_scheduling_period_minutes = 60; + msg_printf(0, MSG_USER_ALERT, "'cpu_scheduling_period_minutes' %s 60.", outrange); + } + } + if (mask.disk_max_used_gb) { + if (global_prefs.disk_max_used_gb < 0 || global_prefs.disk_max_used_gb > ubound) { + global_prefs.disk_max_used_gb = 0; + msg_printf(0, MSG_USER_ALERT, "'disk_max_used_gb' %s 0.", outrange); + } + } + if (mask.disk_max_used_pct) { + if (global_prefs.disk_max_used_pct < 0) { + global_prefs.disk_max_used_pct = 90; + msg_printf(0, MSG_USER_ALERT, "'disk_max_used_pct' %s 90.", outrange); + } else if (global_prefs.disk_max_used_pct > 100) { + global_prefs.disk_max_used_pct = 100; + msg_printf(0, MSG_USER_ALERT, "'disk_max_used_pct' %s 100.", outrange); + } + } + if (mask.disk_min_free_gb) { + if (global_prefs.disk_min_free_gb < 0 || global_prefs.disk_min_free_gb > ubound) { + global_prefs.disk_min_free_gb = 0.1; + msg_printf(0, MSG_USER_ALERT, "'disk_min_free_gb' %s 0.1.", outrange); + } + } + if (mask.vm_max_used_frac) { + if (global_prefs.vm_max_used_frac < 0 || global_prefs.vm_max_used_frac > 1) { + global_prefs.vm_max_used_frac = 0.75; + msg_printf(0, MSG_USER_ALERT, "'vm_max_used_frac' %s 0.75.", outrange); + } + } + if (mask.ram_max_used_busy_frac) { + if (global_prefs.ram_max_used_busy_frac < 0 || global_prefs.ram_max_used_busy_frac > 1) { + global_prefs.ram_max_used_busy_frac = 0.5; + msg_printf(0, MSG_USER_ALERT, "'ram_max_used_busy_frac' %s 0.5.", outrange); + } + } + if (mask.ram_max_used_idle_frac) { + if (global_prefs.ram_max_used_idle_frac < 0 || global_prefs.ram_max_used_idle_frac >1) { +#ifdef ANDROID + global_prefs.ram_max_used_idle_frac = 0.5; + msg_printf(0, MSG_USER_ALERT, "'ram_max_used_idle_frac' %s 0.5.", outrange); +#else + global_prefs.ram_max_used_idle_frac = 0.9; + msg_printf(0, MSG_USER_ALERT, "'ram_max_used_idle_frac' %s 0.9.", outrange); +#endif + } + } + if (mask.max_bytes_sec_up) { + if (global_prefs.max_bytes_sec_up < 0 || global_prefs.max_bytes_sec_up > ubound) { + global_prefs.max_bytes_sec_up = 0; + msg_printf(0, MSG_USER_ALERT, "'max_bytes_sec_up' %s 0.", outrange); + } + } + if (mask.max_bytes_sec_down) { + if (global_prefs.max_bytes_sec_down < 0 || global_prefs.max_bytes_sec_down > ubound) { + global_prefs.max_bytes_sec_down = 0; + msg_printf(0, MSG_USER_ALERT, "'max_bytes_sec_down' %s 0.", outrange); + } + } + if (mask.cpu_usage_limit) { + if (global_prefs.cpu_usage_limit < 0 || global_prefs.cpu_usage_limit > 100) { + global_prefs.cpu_usage_limit = 100; + msg_printf(0, MSG_USER_ALERT, "'cpu_usage_limit' %s 100.", outrange); + } + } + if (mask.niu_cpu_usage_limit) { + if (global_prefs.niu_cpu_usage_limit < 0 || global_prefs.niu_cpu_usage_limit > 100) { + global_prefs.niu_cpu_usage_limit = 100; + msg_printf(0, MSG_USER_ALERT, "'niu_cpu_usage_limit' %s 100.", outrange); + } + } + if (mask.daily_xfer_limit_mb) { + if (global_prefs.daily_xfer_limit_mb < 0 || global_prefs.daily_xfer_limit_mb > ubound) { + global_prefs.daily_xfer_limit_mb = 0; + msg_printf(0, MSG_USER_ALERT, "'daily_xfer_limit_mb' %s 0.", outrange); + } + } + if (mask.daily_xfer_period_days) { + if (global_prefs.daily_xfer_period_days < 0 || global_prefs.daily_xfer_period_days > ubound) { + global_prefs.daily_xfer_period_days = 0; + msg_printf(0, MSG_USER_ALERT, "'daily_xfer_period_days' %s 0.", outrange); + } + } +} + void CLIENT_STATE::print_global_prefs() { msg_printf(NULL, MSG_INFO, "Preferences:"); diff --git a/lib/prefs.cpp b/lib/prefs.cpp index 5016cc23e82..19c48cf719c 100644 --- a/lib/prefs.cpp +++ b/lib/prefs.cpp @@ -331,6 +331,10 @@ int GLOBAL_PREFS::parse_day(XML_PARSER& xp) { while (!xp.get_tag()) { if (!xp.is_tag) continue; if (xp.match_tag("/day_prefs")) { + // The day of the week is validated here because the struct TIME_SPAN + // is an array of a fixed size. For validating the start_hour and + // end_hour, refer to CLIENT_STATE::validate_global_prefs in cs_prefs.cpp. + // if (day_of_week < 0 || day_of_week > 6) return ERR_XML_PARSE; if (has_cpu) { cpu_times.week.set(day_of_week, start_hour, end_hour); @@ -380,7 +384,6 @@ int GLOBAL_PREFS::parse_override( char buf2[256], attrs[256]; bool in_venue = false, in_correct_venue=false; double dtemp; - int itemp; found_venue = false; mask.clear(); @@ -519,39 +522,30 @@ int GLOBAL_PREFS::parse_override( continue; } if (xp.parse_double("work_buf_min_days", work_buf_min_days)) { - if (work_buf_min_days < 0) work_buf_min_days = 0; mask.work_buf_min_days = true; continue; } if (xp.parse_double("work_buf_additional_days", work_buf_additional_days)) { - if (work_buf_additional_days < 0) work_buf_additional_days = 0; mask.work_buf_additional_days = true; continue; } if (xp.parse_double("max_ncpus_pct", max_ncpus_pct)) { - if (max_ncpus_pct < 0) max_ncpus_pct = 0; - if (max_ncpus_pct > 100) max_ncpus_pct = 100; mask.max_ncpus_pct = true; continue; } if (xp.parse_double("niu_max_ncpus_pct", niu_max_ncpus_pct)) { - if (niu_max_ncpus_pct <= 0) niu_max_ncpus_pct = 100; - if (niu_max_ncpus_pct > 100) niu_max_ncpus_pct = 100; mask.niu_max_ncpus_pct = true; continue; } if (xp.parse_int("max_cpus", max_ncpus)) { - if (max_ncpus < 0) max_ncpus = 0; mask.max_ncpus = true; continue; } if (xp.parse_double("disk_interval", disk_interval)) { - if (disk_interval<0) disk_interval = 0; mask.disk_interval = true; continue; } if (xp.parse_double("cpu_scheduling_period_minutes", cpu_scheduling_period_minutes)) { - if (cpu_scheduling_period_minutes < 0.0001) cpu_scheduling_period_minutes = 60; mask.cpu_scheduling_period_minutes = true; continue; } @@ -585,41 +579,27 @@ int GLOBAL_PREFS::parse_override( continue; } if (xp.parse_double("max_bytes_sec_up", max_bytes_sec_up)) { - if (max_bytes_sec_up < 0) max_bytes_sec_up = 0; mask.max_bytes_sec_up = true; continue; } if (xp.parse_double("max_bytes_sec_down", max_bytes_sec_down)) { - if (max_bytes_sec_down < 0) max_bytes_sec_down = 0; mask.max_bytes_sec_down = true; continue; } - if (xp.parse_double("cpu_usage_limit", dtemp)) { - if (dtemp > 0 && dtemp <= 100) { - cpu_usage_limit = dtemp; - mask.cpu_usage_limit = true; - } + if (xp.parse_double("cpu_usage_limit", cpu_usage_limit)) { + mask.cpu_usage_limit = true; continue; } - if (xp.parse_double("niu_cpu_usage_limit", dtemp)) { - if (dtemp <= 0) dtemp = 100; - if (dtemp > 100) dtemp = 100; - niu_cpu_usage_limit = dtemp; + if (xp.parse_double("niu_cpu_usage_limit", niu_cpu_usage_limit)) { mask.niu_cpu_usage_limit = true; continue; } - if (xp.parse_double("daily_xfer_limit_mb", dtemp)) { - if (dtemp >= 0) { - daily_xfer_limit_mb = dtemp; - mask.daily_xfer_limit_mb = true; - } + if (xp.parse_double("daily_xfer_limit_mb", daily_xfer_limit_mb)) { + mask.daily_xfer_limit_mb = true; continue; } - if (xp.parse_int("daily_xfer_period_days", itemp)) { - if (itemp >= 0) { - daily_xfer_period_days = itemp; - mask.daily_xfer_period_days = true; - } + if (xp.parse_int("daily_xfer_period_days", daily_xfer_period_days)) { + mask.daily_xfer_period_days = true; continue; } if (xp.parse_bool("network_wifi_only", network_wifi_only)) {