Separate LXC info fields
This commit is contained in:
parent
7901ad145d
commit
b7e1868f24
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"stdlib.h": "c"
|
"stdlib.h": "c",
|
||||||
|
"process.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
75
src/lxcstat.c
Normal file
75
src/lxcstat.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "lxcstat.h"
|
||||||
|
#include "parsing.h"
|
||||||
|
|
||||||
|
int parseLxcConfigFile(lxcinfo *lxc, char *filedata) {
|
||||||
|
lxc->cpucount = 0;
|
||||||
|
lxc->memlimit = 0;
|
||||||
|
|
||||||
|
char *temp = filedata;
|
||||||
|
lxc->cpucount = findAndParseField(&temp, "cores");
|
||||||
|
temp = filedata;
|
||||||
|
|
||||||
|
lxc->memlimit = findAndParseField(&temp, "memory") * 1024 * 1024;
|
||||||
|
|
||||||
|
char *ptr = strstr(filedata, "hostname:");
|
||||||
|
ptr += strlen("hostname:");
|
||||||
|
while (*ptr == ' ') ptr++;
|
||||||
|
strtok(ptr, "\n\t ");
|
||||||
|
strcpy(lxc->hostname, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int readLxcConfig(lxcinfo *lxc, int lxcid) {
|
||||||
|
char *fname = malloc(1024);
|
||||||
|
char *buffer = malloc(4096);
|
||||||
|
|
||||||
|
sprintf(fname, "/etc/pve/lxc/%d.conf", lxcid);
|
||||||
|
FILE *file = fopen(fname, "rb");
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("Failed to open <%s>: %d\n", fname, errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fread(buffer, 1, 4096, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
parseLxcConfigFile(lxc, buffer);
|
||||||
|
free(buffer);
|
||||||
|
free(fname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lxcinfo *getLXCInfo(lxcinfo **lxcs, int lxcid) {
|
||||||
|
lxcinfo *lxc = *lxcs;
|
||||||
|
while (lxc != NULL) {
|
||||||
|
if (lxc->lxcid == lxcid) return lxc;
|
||||||
|
lxc = lxc->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
lxc = malloc(sizeof(lxcinfo));
|
||||||
|
lxc->lxcid = lxcid;
|
||||||
|
|
||||||
|
if (readLxcConfig(lxc, lxcid)) {
|
||||||
|
// failed to read LXC
|
||||||
|
free(lxc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*lxcs == NULL) {
|
||||||
|
// head was NULL - first LXC
|
||||||
|
*lxcs = lxc;
|
||||||
|
lxc->head = lxc;
|
||||||
|
lxc->tail = lxc;
|
||||||
|
lxc->next = NULL;
|
||||||
|
} else {
|
||||||
|
// other LXCs exist - chain to tail
|
||||||
|
(*lxcs)->tail->next = lxc;
|
||||||
|
(*lxcs)->tail = lxc;
|
||||||
|
lxc->head = *lxcs;
|
||||||
|
lxc->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lxc;
|
||||||
|
}
|
||||||
16
src/lxcstat.h
Normal file
16
src/lxcstat.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef LXCSTAT_H
|
||||||
|
#define LXCSTAT_H
|
||||||
|
|
||||||
|
typedef struct _lxc_info {
|
||||||
|
struct _lxc_info *next;
|
||||||
|
struct _lxc_info *head;
|
||||||
|
struct _lxc_info *tail; // only valid for head lxcinfo
|
||||||
|
int lxcid;
|
||||||
|
int cpucount;
|
||||||
|
int memlimit;
|
||||||
|
char hostname[128];
|
||||||
|
} lxcinfo;
|
||||||
|
|
||||||
|
lxcinfo *getLXCInfo(lxcinfo **lxcs, int lxcid);
|
||||||
|
|
||||||
|
#endif
|
||||||
44
src/parsing.h
Normal file
44
src/parsing.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef PARSING_H
|
||||||
|
#define PARSING_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static inline uint64_t fast_str2ull(char **str) {
|
||||||
|
uint64_t result = 0;
|
||||||
|
int maxlen = 20; // length of maximum value of 18446744073709551615
|
||||||
|
|
||||||
|
while (maxlen-- && **str >= '0' && **str <= '9') {
|
||||||
|
result *= 10;
|
||||||
|
result += **str - '0';
|
||||||
|
(*str)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t fast_str2ll(char **str) {
|
||||||
|
bool neg = false;
|
||||||
|
|
||||||
|
if (**str == '-') {
|
||||||
|
neg = true;
|
||||||
|
(*str)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t res = fast_str2ull(str);
|
||||||
|
int64_t result = (int64_t)res;
|
||||||
|
|
||||||
|
return neg ? -result : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t findAndParseField(char **filedata, char *fld) {
|
||||||
|
char *field = strstr(*filedata, fld);
|
||||||
|
if (!field) return -1;
|
||||||
|
while (*field < '0' || *field > '9') field++;
|
||||||
|
*filedata = field;
|
||||||
|
uint64_t val = fast_str2ull(filedata);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -8,17 +8,16 @@ typedef struct st_process {
|
|||||||
struct st_process *next;
|
struct st_process *next;
|
||||||
struct st_process *prev;
|
struct st_process *prev;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
char cpuset[128];
|
||||||
|
int tgid;
|
||||||
// attributes identifying thread
|
// attributes identifying thread
|
||||||
int lxc;
|
int lxc;
|
||||||
int pid;
|
int pid;
|
||||||
int ppid;
|
int ppid;
|
||||||
int tgid;
|
|
||||||
int level;
|
int level;
|
||||||
char label[128];
|
char label[128];
|
||||||
char cpuset[128];
|
|
||||||
char lxcname[128];
|
|
||||||
int iskernel;
|
|
||||||
// statistics - each outputs 1 line per process
|
// statistics - each outputs 1 line per process
|
||||||
|
int iskernel;
|
||||||
uint64_t cpuTime;
|
uint64_t cpuTime;
|
||||||
uint64_t childCpuTime;
|
uint64_t childCpuTime;
|
||||||
uint64_t nThreads;
|
uint64_t nThreads;
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
int main3(int argc, char *argv[]) {
|
|
||||||
DIR *procdir = opendir("/proc");
|
|
||||||
struct dirent *pDirent;
|
|
||||||
|
|
||||||
while ((pDirent = readdir(procdir)) != NULL) {
|
|
||||||
printf("[%s]\n", pDirent->d_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
573
src/server.c
573
src/server.c
@ -1,362 +1,333 @@
|
|||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
#include "lxcstat.h"
|
||||||
|
#include "parsing.h"
|
||||||
|
|
||||||
#ifndef PF_KTHREAD
|
#ifndef PF_KTHREAD
|
||||||
# define PF_KTHREAD 0x00200000
|
#define PF_KTHREAD 0x00200000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline uint64_t fast_str2ull(char** str) {
|
#define skipRange(inclusive, exclusive) \
|
||||||
uint64_t result = 0;
|
for (int i##inclusive = 0; i##inclusive < exclusive - inclusive; \
|
||||||
int maxlen = 20; // length of maximum value of 18446744073709551615
|
i##inclusive++) \
|
||||||
|
location = strchr(location, ' ') + 1;
|
||||||
while (maxlen-- && **str >= '0' && **str <= '9') {
|
|
||||||
result *= 10;
|
|
||||||
result += **str - '0';
|
|
||||||
(*str)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int64_t fast_str2ll(char** str) {
|
|
||||||
bool neg = false;
|
|
||||||
|
|
||||||
if (**str == '-') {
|
|
||||||
neg = true;
|
|
||||||
(*str)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t res = fast_str2ull(str);
|
|
||||||
int64_t result = (int64_t) res;
|
|
||||||
|
|
||||||
return neg ? -result : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define skipRange(inclusive,exclusive) \
|
|
||||||
for (int i##inclusive=0; i##inclusive<exclusive-inclusive; i##inclusive++) \
|
|
||||||
location = strchr(location, ' ') + 1;
|
|
||||||
|
|
||||||
int parseStatFile(Process *proc, char *filedata) {
|
int parseStatFile(Process *proc, char *filedata) {
|
||||||
char *location = filedata;
|
char *location = filedata;
|
||||||
// (1) pid - %d
|
// (1) pid - %d
|
||||||
proc->pid = fast_str2ull(&location);
|
proc->pid = fast_str2ull(&location);
|
||||||
location += 2;
|
location += 2;
|
||||||
|
|
||||||
// (2) comm - %s
|
// (2) comm - %s
|
||||||
char *end = strrchr(location, ')');
|
char *end = strrchr(location, ')');
|
||||||
size_t length = end - location;
|
size_t length = end - location;
|
||||||
memcpy(proc->label, location, length);
|
memcpy(proc->label, location, length);
|
||||||
proc->label[length] = 0;
|
proc->label[length] = 0;
|
||||||
location = end + 2;
|
location = end + 2;
|
||||||
|
|
||||||
// (3) State - %c
|
// (3) State - %c
|
||||||
location += 2;
|
location += 2;
|
||||||
|
|
||||||
// (4) ppid - %d
|
// (4) ppid - %d
|
||||||
proc->ppid = fast_str2ull(&location);
|
proc->ppid = fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
// skip [5 - 9)
|
// skip [5 - 9)
|
||||||
skipRange(5, 9);
|
skipRange(5, 9);
|
||||||
|
|
||||||
// (9) flags - %u
|
// (9) flags - %u
|
||||||
proc->flags = fast_str2ull(&location);
|
proc->flags = fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
proc->iskernel = (proc->flags & PF_KTHREAD) ? true : false;
|
proc->iskernel = (proc->flags & PF_KTHREAD) ? true : false;
|
||||||
|
|
||||||
// skip [10 - 14)
|
// skip [10 - 14)
|
||||||
skipRange(10, 14);
|
skipRange(10, 14);
|
||||||
|
|
||||||
// (14) utime - %lu
|
// (14) utime - %lu
|
||||||
proc->cpuTime = fast_str2ull(&location);
|
proc->cpuTime = fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
// (15) stime - %lu
|
// (15) stime - %lu
|
||||||
proc->cpuTime += fast_str2ull(&location);
|
proc->cpuTime += fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
// (16) cutime - %lu
|
// (16) cutime - %lu
|
||||||
proc->childCpuTime = fast_str2ull(&location);
|
proc->childCpuTime = fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
// (17) cstime - %lu
|
// (17) cstime - %lu
|
||||||
proc->childCpuTime += fast_str2ull(&location);
|
proc->childCpuTime += fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
// skip 18-19
|
// skip 18-19
|
||||||
skipRange(18, 20);
|
skipRange(18, 20);
|
||||||
|
|
||||||
// (20) num_threads - %ld
|
// (20) num_threads - %ld
|
||||||
proc->nThreads = fast_str2ull(&location);
|
proc->nThreads = fast_str2ull(&location);
|
||||||
location += 1;
|
location += 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64_t findAndParseField(char **filedata, char *fld) {
|
|
||||||
char *field = strstr(*filedata, fld);
|
|
||||||
if (!field) return -1;
|
|
||||||
while (*field < '0' || *field > '9') field++;
|
|
||||||
*filedata = field;
|
|
||||||
uint64_t val = fast_str2ull(filedata);
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseStatusFile(Process *proc, char *filedata) {
|
int parseStatusFile(Process *proc, char *filedata) {
|
||||||
proc->tgid = findAndParseField(&filedata, "Tgid");
|
proc->tgid = findAndParseField(&filedata, "Tgid");
|
||||||
proc->pid = findAndParseField(&filedata, "Pid");
|
proc->pid = findAndParseField(&filedata, "Pid");
|
||||||
|
|
||||||
if (proc->pid != proc->tgid) return -1; // ignore child threads, as their stats are the same as the parent
|
if (proc->pid != proc->tgid)
|
||||||
|
return -1; // ignore child threads, as their stats are the same as the
|
||||||
|
// parent
|
||||||
|
|
||||||
proc->resident = 1024 * findAndParseField(&filedata, "VmRSS");
|
proc->resident = 1024 * findAndParseField(&filedata, "VmRSS");
|
||||||
proc->swap = 1024 * findAndParseField(&filedata, "VmSwap");
|
proc->swap = 1024 * findAndParseField(&filedata, "VmSwap");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseIOFile(Process *proc, char *filedata) {
|
int parseIOFile(Process *proc, char *filedata) {
|
||||||
proc->read = findAndParseField(&filedata, "read_bytes");
|
proc->read = findAndParseField(&filedata, "read_bytes");
|
||||||
proc->written = findAndParseField(&filedata, "write_bytes");
|
proc->written = findAndParseField(&filedata, "write_bytes");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *readProcesses(char *procdir) {
|
char *readProcesses(char *procdir) {
|
||||||
int len;
|
int len;
|
||||||
struct dirent *pDirent;
|
struct dirent *pDirent;
|
||||||
DIR *pDir;
|
DIR *pDir;
|
||||||
|
|
||||||
// Ensure we can open directory.
|
// Ensure we can open directory.
|
||||||
|
|
||||||
pDir = opendir(procdir);
|
pDir = opendir(procdir);
|
||||||
if (pDir == NULL) {
|
if (pDir == NULL) {
|
||||||
printf("Cannot open directory '%s'\n", procdir);
|
printf("Cannot open directory '%s'\n", procdir);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each entry.
|
||||||
|
|
||||||
|
char *buffer = malloc(4096);
|
||||||
|
char *fname = malloc(1024);
|
||||||
|
char first;
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
Process *cur = malloc(sizeof(Process));
|
||||||
|
cur->prev = NULL;
|
||||||
|
cur->next = NULL;
|
||||||
|
Process *head = cur;
|
||||||
|
lxcinfo *lxcs = NULL;
|
||||||
|
|
||||||
|
while ((pDirent = readdir(pDir)) != NULL) {
|
||||||
|
first = pDirent->d_name[0];
|
||||||
|
if (first < '0' || first > '9') continue;
|
||||||
|
sprintf(fname, "/proc/%s/status", pDirent->d_name);
|
||||||
|
file = fopen(fname, "rb");
|
||||||
|
if (file == NULL) continue;
|
||||||
|
fread(buffer, 1, 4096, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (parseStatusFile(cur, buffer)) continue;
|
||||||
|
|
||||||
|
// truncate 'status' to 'stat'
|
||||||
|
len = strlen(fname);
|
||||||
|
fname[len - 2] = 0;
|
||||||
|
file = fopen(fname, "rb");
|
||||||
|
if (file == NULL) continue;
|
||||||
|
fread(buffer, 1, 4096, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (parseStatFile(cur, buffer)) continue;
|
||||||
|
|
||||||
|
sprintf(fname, "/proc/%s/io", pDirent->d_name);
|
||||||
|
file = fopen(fname, "rb");
|
||||||
|
if (file == NULL) continue;
|
||||||
|
fread(buffer, 1, 4096, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (parseIOFile(cur, buffer)) continue;
|
||||||
|
|
||||||
|
sprintf(fname, "/proc/%s/cpuset", pDirent->d_name);
|
||||||
|
file = fopen(fname, "rb");
|
||||||
|
if (file == NULL) goto nextProcess;
|
||||||
|
fread(cur->cpuset, 1, sizeof(cur->cpuset), file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
strtok(cur->cpuset, "\n\t ");
|
||||||
|
char *lxcTag = "/lxc/";
|
||||||
|
if (memcmp(cur->cpuset, lxcTag, strlen(lxcTag)) == 0) {
|
||||||
|
// Resides in LXC -- read file and tag
|
||||||
|
sscanf(cur->cpuset, "/lxc/%d/ns", &cur->lxc);
|
||||||
|
if (getLXCInfo(&lxcs, cur->lxc) == NULL)
|
||||||
|
printf("Failed to read LXC config <%d>\n", cur->lxc);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cur->lxc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each entry.
|
nextProcess:
|
||||||
|
cur->next = malloc(sizeof(Process));
|
||||||
|
cur->next->prev = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
char *buffer = malloc(4096);
|
// clean up unused last node
|
||||||
char *fname = malloc(1024);
|
cur = cur->prev;
|
||||||
char first;
|
free(cur->next);
|
||||||
FILE *file;
|
cur->next = NULL;
|
||||||
|
|
||||||
Process *cur = malloc(sizeof(Process));
|
int clocks = sysconf(_SC_CLK_TCK);
|
||||||
cur->prev = NULL;
|
char *output = malloc(8 * 1024 * 1024);
|
||||||
cur->next = NULL;
|
char *ptr = output;
|
||||||
Process *head = cur;
|
|
||||||
|
|
||||||
while ((pDirent = readdir(pDir)) != NULL) {
|
cur = head;
|
||||||
first = pDirent->d_name[0];
|
while (cur != NULL) {
|
||||||
if (first < '0' || first > '9') continue;
|
// create process descriptor
|
||||||
sprintf(fname, "/proc/%s/status", pDirent->d_name);
|
sprintf(buffer,
|
||||||
file = fopen(fname, "rb");
|
"pid=\"%d\",ppid=\"%d\",label=\"%s\",lxc=\"%d\",level=\"%d\"",
|
||||||
if (file == NULL) continue;
|
cur->pid, cur->ppid, cur->label, cur->lxc, cur->level);
|
||||||
fread(buffer, 1, 4096, file);
|
ptr += sprintf(ptr, "process_cpu_time_seconds{%s} %f\n", buffer, (double) cur->cpuTime / clocks);
|
||||||
fclose(file);
|
ptr += sprintf(ptr, "process_child_cpu_time_seconds{%s} %f\n", buffer,(double) cur->childCpuTime / clocks);
|
||||||
|
ptr += sprintf(ptr, "process_num_threads{%s} %llu\n", buffer, cur->nThreads);
|
||||||
|
ptr += sprintf(ptr, "process_resident_bytes{%s} %llu\n", buffer, cur->resident);
|
||||||
|
ptr += sprintf(ptr, "process_swap_bytes{%s} %llu\n", buffer, cur->swap);
|
||||||
|
ptr += sprintf(ptr, "process_fileio_bytes_written{%s} %llu\n", buffer, cur->written);
|
||||||
|
ptr += sprintf(ptr, "process_fileio_bytes_read{%s} %llu\n", buffer, cur->read);
|
||||||
|
ptr += sprintf(ptr, "process_is_kernel_process{%s} %d\n", buffer, cur->iskernel);
|
||||||
|
// free and proceed
|
||||||
|
Process *prev = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
free(prev);
|
||||||
|
}
|
||||||
|
|
||||||
if (parseStatusFile(cur, buffer)) continue;
|
lxcinfo *lxc = lxcs;
|
||||||
|
while (lxc != NULL) {
|
||||||
|
sprintf(buffer, "lxc=\"%d\",lxcname=\"%s\"", lxc->lxcid, lxc->hostname);
|
||||||
|
ptr += sprintf(ptr, "lxc_cpu_core_count{%s} %u\n", buffer, lxc->cpucount);
|
||||||
|
ptr += sprintf(ptr, "lxc_memory_limit_bytes{%s} %llu\n", buffer, lxc->memlimit);
|
||||||
|
// free and proceed
|
||||||
|
lxcinfo *prev = lxc;
|
||||||
|
lxc = lxc->next;
|
||||||
|
free(prev);
|
||||||
|
}
|
||||||
|
|
||||||
// truncate 'status' to 'stat'
|
closedir(pDir);
|
||||||
len = strlen(fname);
|
free(buffer);
|
||||||
fname[len-2] = 0;
|
free(fname);
|
||||||
file = fopen(fname, "rb");
|
return output;
|
||||||
if (file == NULL) continue;
|
|
||||||
fread(buffer, 1, 4096, file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if (parseStatFile(cur, buffer)) continue;
|
|
||||||
|
|
||||||
sprintf(fname, "/proc/%s/io", pDirent->d_name);
|
|
||||||
file = fopen(fname, "rb");
|
|
||||||
if (file == NULL) continue;
|
|
||||||
fread(buffer, 1, 4096, file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if (parseIOFile(cur, buffer)) continue;
|
|
||||||
|
|
||||||
sprintf(fname, "/proc/%s/cpuset", pDirent->d_name);
|
|
||||||
file = fopen(fname, "rb");
|
|
||||||
if (file == NULL) goto nextProcess;
|
|
||||||
fread(cur->cpuset, 1, sizeof(cur->cpuset), file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
strtok(cur->cpuset, "\n\t ");
|
|
||||||
char *lxcTag = "/lxc/";
|
|
||||||
if (memcmp(cur->cpuset, lxcTag, strlen(lxcTag)) == 0) {
|
|
||||||
// Resides in LXC -- read file and tag
|
|
||||||
sscanf(cur->cpuset, "/lxc/%d/ns", &cur->lxc);
|
|
||||||
sprintf(fname, "/etc/pve/lxc/%d.conf", cur->lxc);
|
|
||||||
file = fopen(fname, "rb");
|
|
||||||
if (file == NULL) goto nextProcess;
|
|
||||||
fread(buffer, 1, 4096, file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
char *ptr = strstr(buffer, "hostname:");
|
|
||||||
ptr += strlen("hostname:");
|
|
||||||
while (*ptr == ' ') ptr++;
|
|
||||||
strtok(ptr, "\n\t ");
|
|
||||||
strcpy(cur->lxcname, ptr);
|
|
||||||
} else {
|
|
||||||
cur->lxcname[0] = 0;
|
|
||||||
cur->lxc = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
nextProcess:
|
|
||||||
cur->next = malloc(sizeof(Process));
|
|
||||||
cur->next->prev = cur;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up unused last node
|
|
||||||
cur = cur->prev;
|
|
||||||
free(cur->next);
|
|
||||||
cur->next = NULL;
|
|
||||||
|
|
||||||
int clocks = sysconf(_SC_CLK_TCK);
|
|
||||||
char *output = malloc(8*1024*1024);
|
|
||||||
char *ptr = output;
|
|
||||||
|
|
||||||
cur = head;
|
|
||||||
while (cur != NULL) {
|
|
||||||
// create process descriptor
|
|
||||||
sprintf(buffer, "pid=\"%d\",ppid=\"%d\",label=\"%s\",kernel=\"%d\",ctid=\"%d\",lxc=\"%s\"", cur->pid, cur->ppid, cur->label, cur->iskernel, cur->lxc, cur->lxcname);
|
|
||||||
ptr += sprintf(ptr, "proc_cpu_time{%s} %f\n", buffer, (double) cur->cpuTime / clocks);
|
|
||||||
ptr += sprintf(ptr, "proc_child_cpu_time{%s} %f\n", buffer, (double) cur->childCpuTime / clocks);
|
|
||||||
ptr += sprintf(ptr, "proc_num_threads{%s} %llu\n", buffer, cur->nThreads);
|
|
||||||
ptr += sprintf(ptr, "proc_resident_bytes{%s} %llu\n", buffer, cur->resident);
|
|
||||||
ptr += sprintf(ptr, "proc_swap_bytes{%s} %llu\n", buffer, cur->swap);
|
|
||||||
ptr += sprintf(ptr, "proc_fileio_bytes_written{%s} %llu\n", buffer, cur->written);
|
|
||||||
ptr += sprintf(ptr, "proc_fileio_bytes_read{%s} %llu\n", buffer, cur->read);
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur = head;
|
|
||||||
while (cur != NULL) {
|
|
||||||
Process *prev = cur;
|
|
||||||
cur = cur->next;
|
|
||||||
free(prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
closedir(pDir);
|
|
||||||
free(buffer);
|
|
||||||
free(fname);
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BUFFER_SIZE 1024
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
void handle_client(int client_socket) {
|
void handle_client(int client_socket) {
|
||||||
char *data = readProcesses("/proc");
|
char *data = readProcesses("/proc");
|
||||||
int length = strlen(data);
|
int length = strlen(data);
|
||||||
printf("Got data of length: %d\n", length);
|
printf("Got data of length: %d\n", length);
|
||||||
|
|
||||||
// HTTP response
|
// HTTP response
|
||||||
const char *http_headers_fmt =
|
const char *http_headers_fmt =
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: text/plain\r\n"
|
"Content-Type: text/plain\r\n"
|
||||||
"Content-Length: %u\r\n"
|
"Content-Length: %u\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n";
|
"\r\n";
|
||||||
|
|
||||||
char headers[BUFFER_SIZE];
|
char headers[BUFFER_SIZE];
|
||||||
sprintf(headers, http_headers_fmt, length);
|
sprintf(headers, http_headers_fmt, length);
|
||||||
|
|
||||||
printf("Sending headers\n");
|
|
||||||
if (send(client_socket, headers, strlen(headers), 0) == -1) {
|
|
||||||
printf("Failed to send headers\n");
|
|
||||||
free(data);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
printf("Sent headers\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the response to the client
|
|
||||||
int total_sent = 0;
|
|
||||||
|
|
||||||
while (total_sent < length) {
|
|
||||||
int amt = length - total_sent;
|
|
||||||
int sent = send(client_socket, data+total_sent, amt, 0);
|
|
||||||
printf("Tried sending %d actually sent %d\n", amt, sent);
|
|
||||||
total_sent += sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Closing connection\n");
|
|
||||||
// Close the client socket
|
|
||||||
shutdown(client_socket, SHUT_WR);
|
|
||||||
sleep(1);
|
|
||||||
close(client_socket);
|
|
||||||
|
|
||||||
|
printf("Sending headers\n");
|
||||||
|
if (send(client_socket, headers, strlen(headers), 0) == -1) {
|
||||||
|
printf("Failed to send headers\n");
|
||||||
free(data);
|
free(data);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
printf("Sent headers\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the response to the client
|
||||||
|
int total_sent = 0;
|
||||||
|
|
||||||
|
while (total_sent < length) {
|
||||||
|
int amt = length - total_sent;
|
||||||
|
int sent = send(client_socket, data + total_sent, amt, 0);
|
||||||
|
printf("Tried sending %d actually sent %d\n", amt, sent);
|
||||||
|
total_sent += sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Closing connection\n");
|
||||||
|
// Close the client socket
|
||||||
|
shutdown(client_socket, SHUT_WR);
|
||||||
|
sleep(1);
|
||||||
|
close(client_socket);
|
||||||
|
|
||||||
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
int port = 9101;
|
||||||
|
|
||||||
int port = 9101;
|
if (argc == 1) {
|
||||||
|
char *buf = readProcesses("/proc");
|
||||||
if (argc == 1) {
|
if (buf == NULL) return 4;
|
||||||
char *buf = readProcesses("/proc");
|
printf(buf);
|
||||||
if (buf == NULL) return 4;
|
|
||||||
printf(buf);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
port = atoi(argv[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int server_socket, client_socket;
|
|
||||||
struct sockaddr_in server_addr, client_addr;
|
|
||||||
socklen_t addr_len = sizeof(client_addr);
|
|
||||||
|
|
||||||
// Create the server socket
|
|
||||||
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
|
||||||
perror("Socket creation failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the server address
|
|
||||||
server_addr.sin_family = AF_INET;
|
|
||||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
server_addr.sin_port = htons(port);
|
|
||||||
|
|
||||||
// Bind the socket to the specified port
|
|
||||||
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
|
|
||||||
perror("Bind failed");
|
|
||||||
close(server_socket);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for incoming connections
|
|
||||||
if (listen(server_socket, 5) == -1) {
|
|
||||||
perror("Listen failed");
|
|
||||||
close(server_socket);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Server is listening on port %d\n", port);
|
|
||||||
|
|
||||||
// Accept and handle incoming connections
|
|
||||||
while (1) {
|
|
||||||
if ((client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len)) == -1) {
|
|
||||||
perror("Accept failed");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the client in a separate function
|
|
||||||
handle_client(client_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the server socket (this won't actually be reached in this example)
|
|
||||||
close(server_socket);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
port = atoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_socket, client_socket;
|
||||||
|
struct sockaddr_in server_addr, client_addr;
|
||||||
|
socklen_t addr_len = sizeof(client_addr);
|
||||||
|
|
||||||
|
// Create the server socket
|
||||||
|
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||||
|
perror("Socket creation failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the server address
|
||||||
|
server_addr.sin_family = AF_INET;
|
||||||
|
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
server_addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
// Bind the socket to the specified port
|
||||||
|
if (bind(server_socket, (struct sockaddr *)&server_addr,
|
||||||
|
sizeof(server_addr)) == -1) {
|
||||||
|
perror("Bind failed");
|
||||||
|
close(server_socket);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for incoming connections
|
||||||
|
if (listen(server_socket, 5) == -1) {
|
||||||
|
perror("Listen failed");
|
||||||
|
close(server_socket);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Server is listening on port %d\n", port);
|
||||||
|
|
||||||
|
// Accept and handle incoming connections
|
||||||
|
while (1) {
|
||||||
|
if ((client_socket = accept(server_socket, (struct sockaddr *)&client_addr,
|
||||||
|
&addr_len)) == -1) {
|
||||||
|
perror("Accept failed");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the client in a separate function
|
||||||
|
handle_client(client_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the server socket (this won't actually be reached in this example)
|
||||||
|
close(server_socket);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user