|
| 1 | +/* |
| 2 | +htop - FlexMeter.c |
| 3 | +(C) 2024 Stoyan Bogdanov |
| 4 | +Released under the GNU GPLv2+, see the COPYING file |
| 5 | +in the source distribution for its full text. |
| 6 | +*/ |
| 7 | + |
| 8 | +#include <dirent.h> |
| 9 | +#include <pwd.h> |
| 10 | +#include <sys/time.h> |
| 11 | +#include <sys/types.h> |
| 12 | +#include <time.h> |
| 13 | +#include <unistd.h> |
| 14 | + |
| 15 | +#include "CRT.h" |
| 16 | +#include "config.h" |
| 17 | +#include "FlexMeter.h" |
| 18 | +#include "Object.h" |
| 19 | + |
| 20 | + |
| 21 | +#define FLEX_CFG_FOLDER ".config/htop/FlexMeter" |
| 22 | + |
| 23 | +typedef struct { |
| 24 | + char* name; |
| 25 | + char* command; |
| 26 | + char* type; |
| 27 | + char* caption; |
| 28 | + char* uiName; |
| 29 | +} _flex_meter; |
| 30 | + |
| 31 | +_flex_meter meter_list[METERS_LIST_SIZE]; |
| 32 | + |
| 33 | +static int meters_count = 0; |
| 34 | + |
| 35 | +static const int DateMeter_attributes[] = { |
| 36 | + FLEX |
| 37 | +}; |
| 38 | + |
| 39 | +MeterClass* FlexMeter_class = NULL; |
| 40 | + |
| 41 | +static int check_for_meters(void); |
| 42 | + |
| 43 | +static bool parse_input(_flex_meter *meter, char* line) |
| 44 | +{ |
| 45 | + switch(line[0]) |
| 46 | + { |
| 47 | + case 'n': |
| 48 | + if (String_startsWith(line, "name=")) { |
| 49 | + xAsprintf(&meter->uiName, "Flex: %s", line + 5); |
| 50 | + } |
| 51 | + break; |
| 52 | + case 'c': |
| 53 | + if (String_startsWith(line, "command=")) { |
| 54 | + meter->command = xStrdup(line + 8); |
| 55 | + } else if (String_startsWith(line, "caption=")) { |
| 56 | + meter->caption = xStrdup(line + 8); |
| 57 | + } |
| 58 | + break; |
| 59 | + case 't': |
| 60 | + if (String_startsWith(line, "type=")) { |
| 61 | + meter->type = xStrdup(line + 6); |
| 62 | + } |
| 63 | + break; |
| 64 | + default: |
| 65 | + return false; |
| 66 | + } |
| 67 | + |
| 68 | + return true; |
| 69 | +} |
| 70 | + |
| 71 | +static bool load_config(_flex_meter *meter, char* file) |
| 72 | +{ |
| 73 | + bool ret = false; |
| 74 | + FILE* fp = fopen(file, "r"); |
| 75 | + |
| 76 | + if (fp != NULL) { |
| 77 | + char* buff; |
| 78 | + while ((buff = String_readLine(fp)) != NULL) { |
| 79 | + ret = parse_input(meter, buff); |
| 80 | + if (!ret) { |
| 81 | + break; |
| 82 | + } |
| 83 | + } |
| 84 | + free(buff); |
| 85 | + buff = NULL; |
| 86 | + } |
| 87 | + |
| 88 | + fclose(fp); |
| 89 | + return ret; |
| 90 | +} |
| 91 | + |
| 92 | +static int check_for_meters(void) |
| 93 | +{ |
| 94 | + char* path; |
| 95 | + struct dirent* dir; |
| 96 | + struct passwd* pw = getpwuid(getuid()); |
| 97 | + const char* homedir = pw->pw_dir; |
| 98 | + char* home = NULL; |
| 99 | + bool ret; |
| 100 | + |
| 101 | + xAsprintf(&home, "%s/%s", homedir, FLEX_CFG_FOLDER); |
| 102 | + struct stat fileStat; |
| 103 | + |
| 104 | + if (stat(home, &fileStat) < 0) { |
| 105 | + return -1; |
| 106 | + } |
| 107 | + |
| 108 | + uint32_t uid = getuid(); |
| 109 | + |
| 110 | + if ((fileStat.st_uid == uid) && S_ISDIR(fileStat.st_mode) && ((fileStat.st_mode & 0777) == 0700)) { |
| 111 | + DIR* d = opendir(home); |
| 112 | + if (d) { |
| 113 | + while ((dir = readdir(d)) != NULL) { |
| 114 | + if ( dir->d_name[0] == '.') { |
| 115 | + /* We are ignoring all files starting with . like ".Template" |
| 116 | + * and "." ".." directories |
| 117 | + */ |
| 118 | + continue; |
| 119 | + } |
| 120 | + |
| 121 | + meter_list[meters_count].name = xStrdup(dir->d_name); |
| 122 | + xAsprintf(&path, "%s/%s", home, dir->d_name); |
| 123 | + |
| 124 | + if (access(path, R_OK | W_OK | X_OK) == 0) { |
| 125 | + ret = load_config(&meter_list[meters_count], path); |
| 126 | + |
| 127 | + if (ret && (meters_count < MAX_METERS_COUNT)) { |
| 128 | + meters_count++; |
| 129 | + } |
| 130 | + } |
| 131 | + if (path != NULL) { |
| 132 | + free(path); |
| 133 | + path=NULL; |
| 134 | + } |
| 135 | + } |
| 136 | + closedir(d); |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + if (home != NULL) { |
| 141 | + free(home); |
| 142 | + home = NULL; |
| 143 | + } |
| 144 | + return meters_count; |
| 145 | +} |
| 146 | + |
| 147 | +static void FlexMeter_updateValues(Meter* this) |
| 148 | +{ |
| 149 | + for (size_t i = 0 ; i < (size_t)meters_count; i++) { |
| 150 | + if (this->m_ptr == &FlexMeter_class[i] ) { |
| 151 | + char* buff = NULL; |
| 152 | + int ret = -1; |
| 153 | + if (meter_list[i].command) { |
| 154 | + FILE* fd = popen(meter_list[i].command, "r"); |
| 155 | + if (fd) { |
| 156 | + buff = String_readLine(fd); |
| 157 | + ret = pclose(fd); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + if (buff && !ret) { |
| 162 | + xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s", buff); |
| 163 | + } else { |
| 164 | + // Once fail, free command pointer and every time print Error message |
| 165 | + if (meter_list[i].command != NULL) { |
| 166 | + free(meter_list[i].command); |
| 167 | + meter_list[i].command = NULL; |
| 168 | + } |
| 169 | + xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s", "[ERR] Check command"); |
| 170 | + } |
| 171 | + } |
| 172 | + } |
| 173 | +} |
| 174 | + |
| 175 | +const MeterClass FlexMeter_class_template = { |
| 176 | + .super = { |
| 177 | + .extends = Class(Meter), |
| 178 | + .delete = Meter_delete |
| 179 | + }, |
| 180 | + .updateValues = FlexMeter_updateValues, |
| 181 | + .defaultMode = TEXT_METERMODE, |
| 182 | + .maxItems = 1, |
| 183 | + .total = 100, |
| 184 | + .attributes = DateMeter_attributes, |
| 185 | + .name = NULL, |
| 186 | + .uiName = NULL, |
| 187 | + .caption = NULL, |
| 188 | +}; |
| 189 | + |
| 190 | +int load_flex_modules(void) |
| 191 | +{ |
| 192 | + size_t meters_num = check_for_meters(); |
| 193 | + if (!FlexMeter_class && meters_num > 0) { |
| 194 | + FlexMeter_class = (MeterClass*) xCalloc(meters_num, sizeof(MeterClass)); |
| 195 | + for (size_t i = 0 ; i < meters_num; i++) { |
| 196 | + memcpy(&FlexMeter_class[i], &FlexMeter_class_template, sizeof(MeterClass)); |
| 197 | + FlexMeter_class[i].name = (const char*) xStrdup(meter_list[i].name); |
| 198 | + FlexMeter_class[i].uiName = (const char*) xStrdup(meter_list[i].uiName); |
| 199 | + FlexMeter_class[i].caption = (const char*) xStrdup(meter_list[i].caption); |
| 200 | + } |
| 201 | + } |
| 202 | + return meters_num; |
| 203 | +} |
0 commit comments