nuttx-apps/system/resmonitor/fillcpu.c
Old-Ding 6eead56aa9 system: resmonitor: check CPU load reads
Keep the default zero CPU value when the procfs load file cannot be read, and trim only the newline that was actually present. This avoids parsing uninitialized stack data in fillcpu and avoids writing before the showinfo CPU buffer when fgets returns no data.

Signed-off-by: Old-Ding <35417409+Old-Ding@users.noreply.github.com>
2026-07-06 16:31:38 +08:00

237 lines
5.3 KiB
C

/****************************************************************************
* apps/system/resmonitor/fillcpu.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PATH "/proc"
#define CPULOAD "cpuload"
#define LOADAVG "loadavg"
/****************************************************************************
* Private Data
****************************************************************************/
static int go = 1;
/****************************************************************************
* Private Functions
****************************************************************************/
static void handler(int sig)
{
go = 0;
}
static void show_usages(void)
{
syslog(LOG_WARNING,
"Usage: CMD [-c <cpu>] [-f <filepath>] [-a]\n"
"\t\t-c: set cpu occupation that you except, default 80\n"
"\t\t-f: set write payload path, eg. /tmp/payload, program will "
"write to memory if -f not set\n"
"\t\t-a: the cpu (set by -c) is the cpu occupied by this program\n");
exit(1);
}
static float get_cpu(int pid)
{
float cpu = 0;
char filepath[20];
int ret;
if (pid <= 0)
{
ret = snprintf(filepath, 20, "%s/%s", PATH, CPULOAD);
}
else
{
ret = snprintf(filepath, 20, "%s/%d/%s", PATH, pid, LOADAVG);
}
if (ret < 0)
{
/* syslog(LOG_ERR, "snprintf error\n"); */
return cpu;
}
FILE *fp = fopen(filepath, "r");
if (!fp)
{
return cpu;
}
char buf[8];
if (fgets(buf, 8, fp) != NULL)
{
sscanf(buf, "%f", &cpu);
}
fclose(fp);
return cpu;
}
static int writefile(char *filepath, char *buffer1, char *buffer2)
{
if (strlen(filepath) == 0)
{
memset(buffer2, '*', 1024);
memcpy(buffer1, buffer2, 1024);
return 0;
}
else
{
int fd;
memset(buffer1, '*', 1024);
if ((fd = open(filepath, O_WRONLY | O_CREAT, 0700)) <= 0)
{
syslog(LOG_ERR, "open file error\n");
return -1;
}
if (write(fd, buffer1, 1024) <= 0)
{
syslog(LOG_ERR, "write file error\n");
close(fd);
return -1;
}
return close(fd);
}
}
int main(int argc, char *argv[])
{
char buf1[1024];
char buf2[1024];
char filepath[40];
struct timeval sleeptime;
int n = 0;
int lowcount = 0;
int cpu = 80;
bool ispid = false;
int time = 10000;
float fcpu;
int o;
memset(filepath, 0, 40);
go = 1;
if (argc == 1)
{
show_usages();
}
while ((o = getopt(argc, argv, "c:f:a")) != EOF)
{
switch (o)
{
case 'c':
cpu = atoi(optarg);
break;
case 'f':
snprintf(filepath, 40, "%s", optarg);
break;
case 'a':
ispid = true;
break;
default:
show_usages();
break;
}
}
signal(SIGINT, handler);
signal(SIGKILL, handler);
while (go)
{
if (time < 1000)
{
time = 1000;
lowcount++;
if (lowcount > 4)
{
lowcount = 0;
n += 2;
}
}
else if (time > 10000)
{
time = 10000;
n -= 1;
n = (n < 0 ? 0 : n);
}
else
{
lowcount = 0;
}
sleeptime.tv_sec = 0;
sleeptime.tv_usec = time;
select(0, NULL, NULL, NULL, &sleeptime);
if (ispid)
{
fcpu = get_cpu(getpid());
}
else
{
fcpu = get_cpu(0);
}
if (fcpu > cpu)
{
time += 1000;
}
else
{
time -= 1000;
}
for (int i = 0; i < n; i++)
{
if (writefile(filepath, buf1, buf2) != 0)
{
break;
}
}
}
syslog(LOG_INFO, "program complete!\n");
return 0;
}