/* * openuf - sysinfo.c * * Lee estadísticas del sistema para el payload inform. * * ── CPU: /proc/stat ────────────────────────────────────────────────── * * Formato: cpu user nice system idle iowait irq softirq steal * * El uso se calcula con dos snapshots separados en el tiempo: * activo = user + nice + system + irq + softirq + steal * total = activo + idle + iowait * uso % = (Δactivo / Δtotal) × 100 * * ── Memoria: /proc/meminfo ─────────────────────────────────────────── * * MemTotal, MemFree, Buffers, Cached * used = total - free - buffers - cached * * ── Interfaces: /proc/net/dev + /sys/class/net// ───────────── * * /proc/net/dev → contadores acumulados rx/tx * /sys/class/net/speed → velocidad negociada (Mbps) * /sys/class/net/duplex → "full" / "half" * /sys/class/net/operstate → "up" / "down" / "unknown" * /sys/class/net/address → MAC * ioctl SIOCGIFADDR → IP * * ── Radio: iw dev info + survey dump ───────────────────────── * * info: canal actual, potencia TX * survey dump: active/busy/tx/rx time → calcular % utilización */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "sysinfo.h" /* ═══════════════════════════════════════════════════════════════════ Memoria ═══════════════════════════════════════════════════════════════════ */ int sysinfo_mem(mem_stats_t *out) { memset(out, 0, sizeof(*out)); FILE *f = fopen("/proc/meminfo", "r"); if (!f) return -1; char line[128]; while (fgets(line, sizeof(line), f)) { long val = 0; if (sscanf(line, "MemTotal: %ld kB", &val) == 1) out->total_kb = val; else if (sscanf(line, "MemFree: %ld kB", &val) == 1) out->free_kb = val; else if (sscanf(line, "Buffers: %ld kB", &val) == 1) out->buffer_kb = val; else if (sscanf(line, "Cached: %ld kB", &val) == 1) out->cached_kb = val; } fclose(f); return (out->total_kb > 0) ? 0 : -1; } /* ═══════════════════════════════════════════════════════════════════ CPU ═══════════════════════════════════════════════════════════════════ */ typedef struct { unsigned long long user, nice, sys, idle, iowait, irq, softirq, steal; } cpu_snap_t; static cpu_snap_t g_prev = {0}; static int g_valid = 0; static int read_cpu(cpu_snap_t *s) { FILE *f = fopen("/proc/stat", "r"); if (!f) return -1; int r = fscanf(f, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", &s->user, &s->nice, &s->sys, &s->idle, &s->iowait, &s->irq, &s->softirq, &s->steal); fclose(f); return (r >= 4) ? 0 : -1; } int sysinfo_cpu_percent(void) { cpu_snap_t cur; if (read_cpu(&cur) != 0) return 0; if (!g_valid) { g_prev = cur; g_valid = 1; return 0; } unsigned long long da = (cur.user - g_prev.user) + (cur.nice - g_prev.nice) + (cur.sys - g_prev.sys) + (cur.irq - g_prev.irq) + (cur.softirq - g_prev.softirq) + (cur.steal - g_prev.steal); unsigned long long di = (cur.idle - g_prev.idle) + (cur.iowait - g_prev.iowait); unsigned long long dt = da + di; g_prev = cur; return (dt == 0) ? 0 : (int)((da * 100) / dt); } /* ═══════════════════════════════════════════════════════════════════ Interfaz de red ═══════════════════════════════════════════════════════════════════ */ static int read_sysfs_str(const char *iface, const char *file, char *out, size_t sz) { char path[128]; snprintf(path, sizeof(path), "/sys/class/net/%s/%s", iface, file); FILE *f = fopen(path, "r"); if (!f) return -1; char buf[64] = {0}; fgets(buf, sizeof(buf), f); fclose(f); buf[strcspn(buf, "\r\n")] = '\0'; strncpy(out, buf, sz - 1); return (strlen(out) > 0) ? 0 : -1; } static int read_sysfs_int(const char *iface, const char *file) { char buf[32] = {0}; if (read_sysfs_str(iface, file, buf, sizeof(buf)) != 0) return -1; int v = -1; sscanf(buf, "%d", &v); return v; } static void read_ip_ioctl(const char *iface, char *out, size_t sz) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1); if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { struct sockaddr_in *sa = (struct sockaddr_in *)&ifr.ifr_addr; strncpy(out, inet_ntoa(sa->sin_addr), sz - 1); } close(fd); } int sysinfo_iface(const char *ifname, iface_stats_t *out) { memset(out, 0, sizeof(*out)); strncpy(out->name, ifname, sizeof(out->name) - 1); /* MAC, operstate, speed, duplex */ read_sysfs_str(ifname, "address", out->mac, sizeof(out->mac)); char opstate[32] = {0}; read_sysfs_str(ifname, "operstate", opstate, sizeof(opstate)); out->up = (strcmp(opstate, "up") == 0 || strcmp(opstate, "unknown") == 0); int sp = read_sysfs_int(ifname, "speed"); out->speed = (sp > 0) ? sp : 1000; char dup[16] = {0}; read_sysfs_str(ifname, "duplex", dup, sizeof(dup)); out->full_duplex = (strncmp(dup, "full", 4) == 0); /* IP */ read_ip_ioctl(ifname, out->ip, sizeof(out->ip)); /* Contadores de /proc/net/dev */ FILE *f = fopen("/proc/net/dev", "r"); if (!f) return 0; char line[512]; fgets(line, sizeof(line), f); /* skip header lines */ fgets(line, sizeof(line), f); while (fgets(line, sizeof(line), f)) { char *colon = strchr(line, ':'); if (!colon) continue; /* Extraer nombre de interfaz (puede tener espacios al inicio) */ size_t end = colon - line; while (end > 0 && line[end-1] == ' ') end--; size_t start = 0; while (start < end && line[start] == ' ') start++; char name[32] = {0}; size_t nlen = end - start; if (nlen >= sizeof(name)) continue; strncpy(name, line + start, nlen); if (strcmp(name, ifname) != 0) continue; long long rb,rp,re,rd,rf,rframe,rcomp,rmulti; long long tb,tp,te,td,tf,tcol,tcomp,tcarr; sscanf(colon+1, "%lld %lld %lld %lld %lld %lld %lld %lld" " %lld %lld %lld %lld %lld %lld %lld %lld", &rb,&rp,&re,&rd,&rf,&rframe,&rcomp,&rmulti, &tb,&tp,&te,&td,&tf,&tcol,&tcomp,&tcarr); out->rx_bytes = rb; out->rx_packets = rp; out->rx_errors = re; out->rx_dropped = rd; out->rx_multicast= rmulti; out->tx_bytes = tb; out->tx_packets = tp; out->tx_errors = te; out->tx_dropped = td; break; } fclose(f); return 0; } /* ═══════════════════════════════════════════════════════════════════ Radio WiFi ═══════════════════════════════════════════════════════════════════ 1. iw dev wlan0 info → canal y potencia Ejemplo: Interface wlan0 channel 6 (2437 MHz), width: 20 MHz txpower 20.00 dBm 2. iw dev wlan0 survey dump → utilización del canal Buscamos el bloque con "[in use]": frequency: 2437 MHz [in use] channel active time: 12345 ms channel busy time: 987 ms channel transmit time: 456 ms channel receive time: 321 ms Calculamos: cu_total = busy/active × 100 cu_self_tx = transmit/active × 100 cu_self_rx = receive/active × 100 */ int sysinfo_radio(const char *iface, radio_stats_t *out) { memset(out, 0, sizeof(*out)); strncpy(out->iface, iface, sizeof(out->iface) - 1); out->noise = -95; char cmd[128]; /* iw dev info */ snprintf(cmd, sizeof(cmd), "iw dev %s info 2>/dev/null", iface); FILE *p = popen(cmd, "r"); if (!p) return -1; char line[256]; while (fgets(line, sizeof(line), p)) { int ch; float mhz; if (sscanf(line, " channel %d (%f MHz)", &ch, &mhz) == 2) out->channel = ch; float tp; if (sscanf(line, " txpower %f dBm", &tp) == 1) out->tx_power = (int)tp; } pclose(p); /* iw dev survey dump */ snprintf(cmd, sizeof(cmd), "iw dev %s survey dump 2>/dev/null", iface); p = popen(cmd, "r"); if (!p) return 0; long long active=0, busy=0, tx_t=0, rx_t=0; int in_use = 0; while (fgets(line, sizeof(line), p)) { if (strstr(line, "[in use]")) { in_use = 1; active=busy=tx_t=rx_t=0; continue; } if (!in_use) continue; /* Nueva frecuencia sin [in use] resetea el bloque */ if (strstr(line, "frequency:") && !strstr(line, "[in use]")) { in_use = 0; continue; } float noise; long long val; if (sscanf(line, " noise: %f dBm", &noise) == 1) out->noise = (int)noise; if (sscanf(line, " channel active time: %lld ms", &val) == 1) active = val; if (sscanf(line, " channel busy time: %lld ms", &val) == 1) busy = val; if (sscanf(line, " channel transmit time: %lld ms", &val) == 1) tx_t = val; if (sscanf(line, " channel receive time: %lld ms", &val) == 1) rx_t = val; } pclose(p); if (active > 0) { out->cu_total = (int)(busy * 100 / active); out->cu_self_tx = (int)(tx_t * 100 / active); out->cu_self_rx = (int)(rx_t * 100 / active); } /* Número de clientes asociados */ snprintf(cmd, sizeof(cmd), "iw dev %s station dump 2>/dev/null | grep -c '^Station'", iface); p = popen(cmd, "r"); if (p) { fscanf(p, "%d", &out->num_sta); pclose(p); } return 0; }