Files
Arduino/uno-stats-monitor/unomond/gather_stats.c
2024-01-16 00:02:16 -05:00

285 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* UNO Monitor Daemon v.0.1.0
* Kidacro <kidacro@archamedis.net>
* https://kidacro.archamedis.net/git/kidacro/Arduino/src/branch/main/uno-stats-monitor
*
* gather_stats.c - retrieves stats from system
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <sys/sysinfo.h>
#include <sys/vfs.h>
#define MAX_ENTRIES 10
// from monitor_daemon.c
bool file_exists(const char *filename);
void send_stats();
// local function prototypes
void get_stats();
char *trim(char *str);
static void get_cpu_load();
void get_cpu_temp();
void get_free_mem();
void get_free_space();
// external vars (monitor_daemon.c)
extern const char *cpu_temp_file;
extern const char *cpu_fanspeed_file;
extern char *drive_free_space[MAX_ENTRIES];
extern int drive_free_space_count;
extern FILE *log_stream;
extern int debug;
extern int line_length;
extern int line_count;
// stats vars
// TODO: make the character sizes dynamic based on line_length
// src/gather_stats.c:43:6: error: variably modified freespace at file scope <-- damn C
// so we have to make a concession and either #define a max or.... no clue... go back to PHP?
char cpuload[4]; // line 1
char cputemp[6]; // line 1
char freemem[6]; // line 1
char freespace[16]; // line 2
// sysinfo vars
int sysinfo(struct sysinfo *info);
// proto:
// struct sysinfo {
// long uptime; /* Seconds since boot */
// unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
// unsigned long totalram; /* Total usable main memory size */
// unsigned long freeram; /* Available memory size */
// unsigned long sharedram; /* Amount of shared memory */
// unsigned long bufferram; /* Memory used by buffers */
// unsigned long totalswap; /* Total swap space size */
// unsigned long freeswap; /* swap space still available */
// unsigned short procs; /* Number of current processes */
// unsigned long totalhigh; /* Total high memory size */
// unsigned long freehigh; /* Available high memory size */
// unsigned int mem_unit; /* Memory unit size in bytes */
// char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
//};
// trims end of strings
char *trim(char *str)
{
size_t len = 0;
char *frontp = str;
char *endp = NULL;
if( str == NULL ) { return NULL; }
if( str[0] == '\0' ) { return str; }
len = strlen(str);
endp = str + len;
/* Move the front and back pointers to address the first non-whitespace
* characters from each end.
*/
while(isspace((unsigned char) *frontp)) { ++frontp; }
if(endp != frontp) {
while(isspace((unsigned char) *(--endp)) && endp != frontp) {}
}
if(frontp != str && endp == frontp) {
*str = '\0';
}
else if(str + len - 1 != endp) {
*(endp + 1) = '\0';
}
/* Shift the string so that it starts at str so that if it's dynamically
* allocated, we can still free it on the returned pointer. Note the reuse
* of endp to mean the front of the string buffer now.
*/
endp = str;
if(frontp != str) {
while(*frontp) { *endp++ = *frontp++; }
*endp = '\0';
}
return str;
}
// get stats (retreive, combine, and send stats)
// TODO: force trunication for each line to line_length
// no reason to hardcode '24' below when we know the exact line_length
void get_stats()
{
char line_1[24], line_2[24], line_3[24];
get_cpu_load();
get_cpu_temp();
get_free_mem();
get_free_space();
snprintf(line_1,sizeof(line_1),"#1%s%% %sC %sM@",cpuload,cputemp,freemem);
snprintf(line_2,sizeof(line_2),"#2%s@",trim(freespace));
snprintf(line_3,sizeof(line_3),"#-%s@",cpuload);
send_stats(line_1,line_2,line_3);
return;
}
static void get_cpu_load()
{
//static unsigned int lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle;
static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle;
float percent;
static float lastPercent;
int intPercent, read_result = 0;
FILE* file;
unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total;
file = fopen("/proc/stat", "r");
read_result = fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow, &totalSys, &totalIdle);
fclose(file);
// if result cannot be read, set to 0
if(read_result != 4) {
snprintf(&*cpuload, sizeof(0), "%d", 0);
return;
}
// we dont have a good value, use old value
if(totalUser < lastTotalUser || totalUserLow < lastTotalUserLow ||
totalSys < lastTotalSys || totalIdle < lastTotalIdle)
{
percent = -1.0;
//percent = lastPercent;
}
// we have a good value, save it and process it
else
{
total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) + (totalSys - lastTotalSys);
percent = total * 100;
total += (totalIdle - lastTotalIdle);
percent /= total;
lastPercent = percent;
}
if(debug) {
fprintf(log_stream,"lasttotalUser: %llu - lasttotalUserLow: %llu - lasttotalSys: %llu - lasttotalIdle: %llu - lastpercent: %f\n",
lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle, lastPercent);
fprintf(log_stream,"totalUser: %llu - totalUserLow: %llu - totalSys: %llu - totalIdle: %llu - percent: %f\n\n",
totalUser,totalUserLow, totalSys, totalIdle, percent);
}
// save curent values for later comparison
lastTotalUser = totalUser;
lastTotalUserLow = totalUserLow;
lastTotalSys = totalSys;
lastTotalIdle = totalIdle;
// force percent (float) to int
intPercent = percent;
snprintf(&*cpuload, sizeof(intPercent), "%d", intPercent);
return;
}
void get_cpu_temp()
{
FILE* ptr;
char str[10];
// check if file exists
if(!file_exists(cpu_temp_file)) {
return;
}
// opening file in readonly mode
ptr = fopen(&*cpu_temp_file, "r");
if(NULL == ptr) {
fprintf(log_stream,"File cpu_temp_file: %s, can't be opened!\n",cpu_temp_file);
return;
}
while(fgets(str, 10, ptr) != NULL) {
if(debug) {
fprintf(log_stream,"Raw CPU temp: %s\n", str);
}
}
/*
1 decimal place
char a = str[0];
char b = str[1];
char c = str[2];
snprintf(&*cputemp,6,"%c%c.%c",a,b,c);
*/
// no decimals
char a = str[0];
char b = str[1];
snprintf(&*cputemp,6,"%c%c",a,b);
fclose(ptr);
return;
}
void get_free_mem()
{
struct sysinfo info;
int myfreemem;
if(sysinfo(&info) < 0) {
return;
}
if(debug) {
fprintf(log_stream,"RAW free mem: %ld\n",info.freeram);
}
myfreemem = info.freeram / 1024 / 1024;
snprintf(&*freemem,sizeof(freemem),"%d",myfreemem);
return;
}
void get_free_space()
{
struct statfs info;
int n = 0;
char *mydrive;
char myfree_string[line_length];
long unsigned int mytmpfree;
// clear freespace array b4 loop or strcat will keep adding to it causing a buffer overflow
memset(freespace, '\0', sizeof(freespace));
for(n = 0; n < drive_free_space_count; n++) {
mydrive = drive_free_space[n];
statfs(mydrive, &info);
mytmpfree = ((info.f_bavail*4) / 1024 / 1024) + 1;
snprintf(myfree_string,10,"%ldG ",mytmpfree);
strcat(freespace,myfree_string);
if(debug) {
fprintf(log_stream, "My Drive: %s\n"
" block size : %ld,"
" total data blocks : %ld,"
" free blocks for root: %ld,"
" free blocks for user: %ld,"
" free space in G: %ld\n\n",
mydrive, info.f_bsize, info.f_blocks, info.f_bfree, info.f_bavail, mytmpfree);
}
}
return;
}