#include #include #include #include #include #include #include #include #include #include #include "log.h" #include "utils.h" int get_instance_lock(void) { const char *xdg_runtime_dir = getenv("XDG_RUNTIME_DIR"); char tmp_dir[256]; snprintf(tmp_dir, sizeof(tmp_dir), "%s/linuxSmartie.lock", xdg_runtime_dir); const int file = open(tmp_dir, O_CREAT | O_RDWR | O_CLOEXEC, 0600); if (file < 0) { applog(LOG_ERR, "Couldn't create a lock file at %s", tmp_dir); return -1; } if (flock(file, LOCK_EX | LOCK_NB) < 0) { if (errno == EWOULDBLOCK) applog(LOG_ERR, "another instance already running, this one will exit."); else applog(LOG_ERR, "flock failed: %s", strerror(errno)); close(file); return -1; } return 0; } inline void timespec_add_ms(struct timespec *ts, const uint16_t ms) { ts->tv_nsec += ms * 1000000L; if (ts->tv_nsec >= 1000000000L) { ts->tv_sec++; ts->tv_nsec -= 1000000000L; } } inline uint64_t timespec_diff_us(const struct timespec *a, const struct timespec *b) { const int64_t sec = a->tv_sec - b->tv_sec; const int64_t nsec = a->tv_nsec - b->tv_nsec; return sec * 1000000LL + nsec / 1000LL; } inline char *pretty_num(const double num, char *buf, const size_t bufsz) { const uint8_t decimals = (num <= 10.0) ? 2 : (num <= 100.0) ? 1 : 0; snprintf(buf, bufsz, "%.*f", decimals, num); return buf; } inline char *pretty_bytes(const uint64_t bytes, int8_t start_suffix, char *buf, const size_t bufsz) { constexpr char suffix_list[] = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'}; start_suffix *= -1; double bytes_d = (double)bytes; while (bytes_d >= 1024.0) { bytes_d /= 1024.0; start_suffix++; } snprintf(buf, bufsz, "%s%c", P_NUM(bytes_d), suffix_list[MAX(0, start_suffix)]); return buf; } /* path has to have at least 8 free chars at the end for glob */ int get_hwmon_dir(char *path, const size_t bufsz) { glob_t g; strcat(path, "/hwmon*"); if (glob(path, 0, nullptr, &g) == 0) { strlcpy(path, g.gl_pathv[0], bufsz); // same size as hwmon length, careful globfree(&g); return 0; } return -1; } /* instead of building the path here we could build it once in *_detect funcs for each sensor, but thats a lot of paths damn * actual slowdown is in the syscalls anyway, open(), read(), close () */ /* read n bytes from path into buffer */ // file descriptors shouldnt change once opened, so we could open once, cache them, just call read() in the loop, then close all of them on program exit? inline size_t read_file(const char *dir, const char *file, char *buffer, const size_t n) { char path[160]; // bug alert char *nt = stpcpy(path, dir); // nt is a pointer to the null terminator of the copied string strcpy(nt, file); // copy to the null terminator of prev copy, append basically const int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { if (buffer != nullptr) // if its null means we're just checking if it exists at all, so dont log it applog(LOG_ERR, "Error reading %s", path); return 0; } const ssize_t len = read(fd, buffer, n); if (len >= 0 && buffer) buffer[len] = '\0'; close(fd); return len; } inline void fast_read_num_u64(const char *dir, const char *file, char *buf, uint64_t *result, const uint32_t divider) { read_file(dir, file, buf, 32); *result = strtoull(buf, nullptr, 10) / divider; } inline void fast_read_num_u16(const char *dir, const char *file, char *buf, uint16_t *result, const uint32_t divider) { read_file(dir, file, buf, 32); *result = strtol(buf, nullptr, 10) / divider; } inline void fast_read_num_u8(const char *dir, const char *file, char *buf, uint8_t *result, const uint32_t divider) { read_file(dir, file, buf, 32); *result = strtol(buf, nullptr, 10) / divider; } inline void fast_read_num_i16(const char *dir, const char *file, char *buf, int16_t *result, const uint32_t divider) { read_file(dir, file, buf, 32); *result = (int16_t)(strtol(buf, nullptr, 10) / divider); } inline void fast_read_num_f(const char *dir, const char *file, char *buf, float *result, const uint32_t divider) { read_file(dir, file, buf, 32); const uint64_t val = strtoull(buf, nullptr, 10); *result = (float)val / (float)divider; }