Skip to content

Add total CPU % to /info/system endpoint#2297

Merged
DL6ER merged 4 commits into
developmentfrom
new/total_cpu
Mar 5, 2025
Merged

Add total CPU % to /info/system endpoint#2297
DL6ER merged 4 commits into
developmentfrom
new/total_cpu

Conversation

@DL6ER

@DL6ER DL6ER commented Feb 27, 2025

Copy link
Copy Markdown
Member

What does this implement/fix?

Calculate and expose total CPU % for the web interface, see related PR.


Related issue or feature (if applicable): Related to pi-hole/web#3261

Pull request in docs with documentation (if applicable): N/A


By submitting this pull request, I confirm the following:

  1. I have read and understood the contributors guide, as well as this entire template. I understand which branch to base my commits and Pull Requests against.
  2. I have commented my proposed changes within the code.
  3. I am willing to help maintain this change if there are issues with it later.
  4. It is compatible with the EUPL 1.2 license
  5. I have squashed any insignificant commits. (git rebase)

Checklist:

  • The code change is tested and works locally.
  • I based my code and PRs against the repositories developmental branch.
  • I signed off all commits. Pi-hole enforces the DCO for all contributions
  • I signed all my commits. Pi-hole requires signatures to verify authorship
  • I have read the above and my PR is ready for review.

Signed-off-by: DL6ER <dl6er@dl6er.de>
…rnel, older than 2.6.33 released 2010)

Signed-off-by: DL6ER <dl6er@dl6er.de>
@DL6ER DL6ER added the API label Feb 27, 2025
@DL6ER DL6ER requested a review from a team February 27, 2025 05:05
This was referenced Feb 27, 2025
Comment thread src/procps.c
fclose(statfile);

// Guest time is already accounted in usertime
user -= guest;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 1.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the variable user is only used if the sscanf call successfully reads all 10 items. This can be achieved by moving the code that uses user within the conditional block that checks the return value of sscanf.

  1. Move the code that uses user and other variables populated by sscanf within the conditional block that checks the return value of sscanf.
  2. Ensure that the function returns false if sscanf fails to read all 10 items, preventing the use of uninitialized variables.
Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -335,3 +335,16 @@
 
-			break;
+			// Guest time is already accounted in usertime
+			user -= guest;
+			nice -= guest_nice;
+
+			// Fields existing on kernels >= 2.6
+			// (and RHEL's patched kernel 2.4...)
+			const unsigned long long int sys_all = system + irq + softirq;
+			const unsigned long long int virtual = guest + guest_nice;
+			const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
+			*idle_sum = idle + iowait;
+			*total_sum = busy_sum + *idle_sum;
+
+			fclose(statfile);
+			return true;
 		}
@@ -346,16 +359,3 @@
 	fclose(statfile);
-
-	// Guest time is already accounted in usertime
-	user -= guest;
-	nice -= guest_nice;
-
-	// Fields existing on kernels >= 2.6
-	// (and RHEL's patched kernel 2.4...)
-	const unsigned long long int sys_all = system + irq + softirq;
-	const unsigned long long int virtual = guest + guest_nice;
-	const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
-	*idle_sum = idle + iowait;
-	*total_sum = busy_sum + *idle_sum;
-
-	return true;
+	return false;
 }
EOF
@@ -335,3 +335,16 @@

break;
// Guest time is already accounted in usertime
user -= guest;
nice -= guest_nice;

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;
*total_sum = busy_sum + *idle_sum;

fclose(statfile);
return true;
}
@@ -346,16 +359,3 @@
fclose(statfile);

// Guest time is already accounted in usertime
user -= guest;
nice -= guest_nice;

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;
*total_sum = busy_sum + *idle_sum;

return true;
return false;
}
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/procps.c
fclose(statfile);

// Guest time is already accounted in usertime
user -= guest;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 9.

Copilot Autofix

AI over 1 year ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

Comment thread src/procps.c

// Guest time is already accounted in usertime
user -= guest;
nice -= guest_nice;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 2.

Copilot Autofix

AI over 1 year ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

Comment thread src/procps.c

// Guest time is already accounted in usertime
user -= guest;
nice -= guest_nice;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 10.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the variable guest_nice is only used if the sscanf function successfully reads all 10 items. This can be done by adding an explicit check for the return value of sscanf before using guest_nice. If the check fails, the function should return false to prevent further execution with potentially uninitialized variables.

Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -325,6 +325,7 @@
 		{
-			if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+			int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
 			       &user, &nice, &system, &idle,
 			       &iowait, &irq, &softirq, &steal,
-			       &guest, &guest_nice) != 10)
+			       &guest, &guest_nice);
+			if(num_items != 10)
 			{
EOF
@@ -325,6 +325,7 @@
{
if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&user, &nice, &system, &idle,
&iowait, &irq, &softirq, &steal,
&guest, &guest_nice) != 10)
&guest, &guest_nice);
if(num_items != 10)
{
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/procps.c

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 3.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the system variable is only used if the sscanf call successfully reads all 10 items. This can be done by adding a check for the return value of sscanf and ensuring that the subsequent code only executes if the return value is 10. This will prevent the use of uninitialized variables and ensure that the code behaves as expected.

Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -353,9 +353,16 @@
 	// (and RHEL's patched kernel 2.4...)
-	const unsigned long long int sys_all = system + irq + softirq;
-	const unsigned long long int virtual = guest + guest_nice;
-	const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
-	*idle_sum = idle + iowait;
-	*total_sum = busy_sum + *idle_sum;
+			const unsigned long long int sys_all = system + irq + softirq;
+			const unsigned long long int virtual = guest + guest_nice;
+			const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
+			*idle_sum = idle + iowait;
+			*total_sum = busy_sum + *idle_sum;
 
-	return true;
+			fclose(statfile);
+			return true;
+		}
+	}
+
+	log_warn("No CPU line found in /proc/stat");
+	fclose(statfile);
+	return false;
 }
EOF
@@ -353,9 +353,16 @@
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;
*total_sum = busy_sum + *idle_sum;
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;
*total_sum = busy_sum + *idle_sum;

return true;
fclose(statfile);
return true;
}
}

log_warn("No CPU line found in /proc/stat");
fclose(statfile);
return false;
}
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/procps.c

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 6.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the sscanf call returns at least 6 items before using the irq variable. This can be done by adding a check to verify that the return value of sscanf is at least 6 before proceeding with the use of the irq variable. If the return value is less than 6, we should log an error and return false.

Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -325,6 +325,7 @@
 		{
-			if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+			int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
 			       &user, &nice, &system, &idle,
 			       &iowait, &irq, &softirq, &steal,
-			       &guest, &guest_nice) != 10)
+			       &guest, &guest_nice);
+			if(num_items < 6)
 			{
@@ -332,2 +333,8 @@
 				fclose(statfile);
+				return false;
+			}
+			if(num_items != 10)
+			{
+				log_debug(DEBUG_ANY, "Failed to parse all CPU fields in /proc/stat");
+				fclose(statfile);
 				return false;
EOF
@@ -325,6 +325,7 @@
{
if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&user, &nice, &system, &idle,
&iowait, &irq, &softirq, &steal,
&guest, &guest_nice) != 10)
&guest, &guest_nice);
if(num_items < 6)
{
@@ -332,2 +333,8 @@
fclose(statfile);
return false;
}
if(num_items != 10)
{
log_debug(DEBUG_ANY, "Failed to parse all CPU fields in /proc/stat");
fclose(statfile);
return false;
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/procps.c

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 7.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the return value of sscanf is checked to confirm that all expected items were successfully read before using the variables. Specifically, we should check that sscanf returns 10, indicating that all 10 items were read. If the return value is not 10, we should handle the error appropriately, such as by logging an error message and returning false.

Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -325,6 +325,7 @@
 		{
-			if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+			int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
 			       &user, &nice, &system, &idle,
 			       &iowait, &irq, &softirq, &steal,
-			       &guest, &guest_nice) != 10)
+			       &guest, &guest_nice);
+			if(num_items != 10)
 			{
EOF
@@ -325,6 +325,7 @@
{
if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&user, &nice, &system, &idle,
&iowait, &irq, &softirq, &steal,
&guest, &guest_nice) != 10)
&guest, &guest_nice);
if(num_items != 10)
{
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/procps.c
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 8.
Comment thread src/procps.c
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 4.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the idle variable is only used if the sscanf call successfully reads all 10 items. This can be done by adding a check for the return value of sscanf and ensuring that the subsequent code that uses idle is only executed if the check passes.

Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -335,3 +335,16 @@
 
-			break;
+			// Guest time is already accounted in usertime
+			user -= guest;
+			nice -= guest_nice;
+
+			// Fields existing on kernels >= 2.6
+			// (and RHEL's patched kernel 2.4...)
+			const unsigned long long int sys_all = system + irq + softirq;
+			const unsigned long long int virtual = guest + guest_nice;
+			const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
+			*idle_sum = idle + iowait;
+			*total_sum = busy_sum + *idle_sum;
+
+			fclose(statfile);
+			return true;
 		}
@@ -346,16 +359,3 @@
 	fclose(statfile);
-
-	// Guest time is already accounted in usertime
-	user -= guest;
-	nice -= guest_nice;
-
-	// Fields existing on kernels >= 2.6
-	// (and RHEL's patched kernel 2.4...)
-	const unsigned long long int sys_all = system + irq + softirq;
-	const unsigned long long int virtual = guest + guest_nice;
-	const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
-	*idle_sum = idle + iowait;
-	*total_sum = busy_sum + *idle_sum;
-
-	return true;
+	return false;
 }
EOF
@@ -335,3 +335,16 @@

break;
// Guest time is already accounted in usertime
user -= guest;
nice -= guest_nice;

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;
*total_sum = busy_sum + *idle_sum;

fclose(statfile);
return true;
}
@@ -346,16 +359,3 @@
fclose(statfile);

// Guest time is already accounted in usertime
user -= guest;
nice -= guest_nice;

// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;
*total_sum = busy_sum + *idle_sum;

return true;
return false;
}
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/procps.c
const unsigned long long int sys_all = system + irq + softirq;
const unsigned long long int virtual = guest + guest_nice;
const unsigned long long int busy_sum = user + nice + sys_all + steal + virtual;
*idle_sum = idle + iowait;

Check failure

Code scanning / CodeQL

Missing return-value check for a 'scanf'-like function

This variable is read, but may not have been written. It should be guarded by a check that the [call to sscanf](1) returns at least 5.

Copilot Autofix

AI over 1 year ago

To fix the problem, we need to ensure that the sscanf call successfully reads all 10 items before using the variables populated by sscanf. This can be done by adding a check for the return value of sscanf and ensuring that it returns exactly 10. If the return value is not 10, we should handle the error appropriately and avoid using the uninitialized variables.

Suggested changeset 1
src/procps.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/procps.c b/src/procps.c
--- a/src/procps.c
+++ b/src/procps.c
@@ -325,6 +325,7 @@
 		{
-			if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+			int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
 			       &user, &nice, &system, &idle,
 			       &iowait, &irq, &softirq, &steal,
-			       &guest, &guest_nice) != 10)
+			       &guest, &guest_nice);
+			if(num_items != 10)
 			{
EOF
@@ -325,6 +325,7 @@
{
if(sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
int num_items = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&user, &nice, &system, &idle,
&iowait, &irq, &softirq, &steal,
&guest, &guest_nice) != 10)
&guest, &guest_nice);
if(num_items != 10)
{
Copilot is powered by AI and may make mistakes. Always verify output.
@DL6ER

DL6ER commented Feb 27, 2025

Copy link
Copy Markdown
Member Author

Interesting, none of the AI-alerts is real, they were all of type:

grafik

but we do already check for exactly that:
grafik

Comment thread src/api/padd.c
@yubiuser

Copy link
Copy Markdown
Member

@github-actions

github-actions Bot commented Mar 1, 2025

Copy link
Copy Markdown

This pull request has conflicts, please resolve those before we can evaluate the pull request.

Signed-off-by: DL6ER <dl6er@dl6er.de>
@github-actions

github-actions Bot commented Mar 1, 2025

Copy link
Copy Markdown

Conflicts have been resolved.

@DL6ER

DL6ER commented Mar 1, 2025

Copy link
Copy Markdown
Member Author

I removed the last commit that changed the CPU% from FTL to total in the PADD callback.

@pralor-bot

Copy link
Copy Markdown

This pull request has been mentioned on Pi-hole Userspace. There might be relevant details there:

https://discourse.pi-hole.net/t/reimplement-display-of-cpu-temperature-and-load-averages/77390/4

@DL6ER DL6ER merged commit 682610e into development Mar 5, 2025
@DL6ER DL6ER deleted the new/total_cpu branch March 5, 2025 16:16
@PromoFaux PromoFaux mentioned this pull request Mar 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants