diff --git a/src/common/io/io.h b/src/common/io/io.h index 9a76838f4..3fa0df2cb 100644 --- a/src/common/io/io.h +++ b/src/common/io/io.h @@ -69,6 +69,7 @@ ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data); bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer); bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer); +bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer); static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) { @@ -76,6 +77,12 @@ static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) return ffAppendFileBuffer(fileName, buffer); } +static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) +{ + ffStrbufClear(buffer); + return ffAppendFileBufferRelative(dfd, fileName, buffer); +} + //Bit flags, combine with | typedef enum FFPathType { diff --git a/src/common/io/io_unix.c b/src/common/io/io_unix.c index 54689ffae..60b20eba9 100644 --- a/src/common/io/io_unix.c +++ b/src/common/io/io_unix.c @@ -117,6 +117,15 @@ bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) return ffAppendFDBuffer(fd, buffer); } +bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer) +{ + int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC); + if(fd == -1) + return false; + + return ffAppendFDBuffer(fd, buffer); +} + bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* out) { bool result = false; diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 006d7d6c2..5b0027fe0 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -3,39 +3,32 @@ #include "util/stringUtils.h" #include +#include +#include // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power -static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* options, FFlist* results) +static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFlist* results) { - uint32_t dirLength = dir->length; - FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate(); - //type must exist and be "Battery" - ffStrbufAppendS(dir, "/type"); - if (ffReadFileBuffer(dir->chars, &tmpBuffer)) - ffStrbufTrimRightSpace(&tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - + // type must exist and be "Battery" + if (!ffReadFileBufferRelative(dfd, "type", &tmpBuffer)) + return; + ffStrbufTrimRightSpace(&tmpBuffer); if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Battery")) return; - //scope may not exist or must not be "Device" - ffStrbufAppendS(dir, "/scope"); - if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + // scope may not exist or must not be "Device" + if (ffReadFileBufferRelative(dfd, "scope", &tmpBuffer)) ffStrbufTrimRightSpace(&tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device")) return; - //capacity must exist and be not empty - ffStrbufAppendS(dir, "/capacity"); - bool available = ffReadFileBuffer(dir->chars, &tmpBuffer); // This is expensive in my laptop - ffStrbufSubstrBefore(dir, dirLength); - - if (!available) + // capacity must exist and be not empty + // This is expensive in my laptop + if (!ffReadFileBufferRelative(dfd, "capacity", &tmpBuffer)) return; FFBatteryResult* result = ffListAdd(results); @@ -44,55 +37,38 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option //At this point, we have a battery. Try to get as much values as possible. ffStrbufInit(&result->manufacturer); - ffStrbufAppendS(dir, "/manufacturer"); - if (ffReadFileBuffer(dir->chars, &result->manufacturer)) + if (ffReadFileBufferRelative(dfd, "manufacturer", &result->manufacturer)) ffStrbufTrimRightSpace(&result->manufacturer); else if (ffStrEquals(id, "macsmc-battery")) // asahi ffStrbufSetStatic(&result->manufacturer, "Apple Inc."); - ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->modelName); - ffStrbufAppendS(dir, "/model_name"); - if (ffReadFileBuffer(dir->chars, &result->modelName)) + if (ffReadFileBufferRelative(dfd, "model_name", &result->modelName)) ffStrbufTrimRightSpace(&result->modelName); - ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->technology); - ffStrbufAppendS(dir, "/technology"); - if (ffReadFileBuffer(dir->chars, &result->technology)) + if (ffReadFileBufferRelative(dfd, "technology", &result->technology)) ffStrbufTrimRightSpace(&result->technology); - ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->status); - ffStrbufAppendS(dir, "/status"); - if (ffReadFileBuffer(dir->chars, &result->status)) + if (ffReadFileBufferRelative(dfd, "status", &result->status)) ffStrbufTrimRightSpace(&result->status); - ffStrbufSubstrBefore(dir, dirLength); // Unknown, Charging, Discharging, Not charging, Full result->timeRemaining = -1; if (ffStrbufEqualS(&result->status, "Discharging")) { - ffStrbufAppendS(dir, "/time_to_empty_now"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "time_to_empty_now", &tmpBuffer)) result->timeRemaining = (int32_t) ffStrbufToSInt(&tmpBuffer, 0); else { - ffStrbufAppendS(dir, "/charge_now"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "charge_now", &tmpBuffer)) { int64_t chargeNow = ffStrbufToSInt(&tmpBuffer, 0); if (chargeNow > 0) { - ffStrbufAppendS(dir, "/current_now"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "current_now", &tmpBuffer)) { int64_t currentNow = ffStrbufToSInt(&tmpBuffer, INT64_MIN); if (currentNow < 0) currentNow = -currentNow; @@ -109,8 +85,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option else if (ffStrbufEqualS(&result->status, "Unknown")) ffStrbufClear(&result->status); - ffStrbufAppendS(dir, "/capacity_level"); - if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + if (ffReadFileBufferRelative(dfd, "capacity_level", &tmpBuffer)) { ffStrbufTrimRightSpace(&result->manufacturer); if (ffStrbufEqualS(&tmpBuffer, "Critical")) @@ -121,44 +96,29 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option ffStrbufSetStatic(&result->status, "Critical"); } } - ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->serial); - ffStrbufAppendS(dir, "/serial_number"); - if (ffReadFileBuffer(dir->chars, &result->serial)) + if (ffReadFileBufferRelative(dfd, "serial_number", &result->serial)) ffStrbufTrimRightSpace(&result->serial); - ffStrbufSubstrBefore(dir, dirLength); - ffStrbufAppendS(dir, "/cycle_count"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "cycle_count", &tmpBuffer)) { int64_t cycleCount = ffStrbufToSInt(&tmpBuffer, 0); result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount; } ffStrbufInit(&result->manufactureDate); - ffStrbufAppendS(dir, "/manufacture_year"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "manufacture_year", &tmpBuffer)) { int year = (int) ffStrbufToSInt(&tmpBuffer, 0); if (year > 0) { - ffStrbufAppendS(dir, "/manufacture_month"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "manufacture_month", &tmpBuffer)) { int month = (int) ffStrbufToSInt(&tmpBuffer, 0); if (month > 0) { - ffStrbufAppendS(dir, "/manufacture_day"); - available = ffReadFileBuffer(dir->chars, &tmpBuffer); - ffStrbufSubstrBefore(dir, dirLength); - if (available) + if (ffReadFileBufferRelative(dfd, "manufacture_day", &tmpBuffer)) { int day = (int) ffStrbufToSInt(&tmpBuffer, 0); if (day > 0) @@ -172,10 +132,8 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option result->temperature = FF_BATTERY_TEMP_UNSET; if (options->temp) { - ffStrbufAppendS(dir, "/temp"); - if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + if (ffReadFileBufferRelative(dfd, "temp", &tmpBuffer)) result->temperature = ffStrbufToDouble(&tmpBuffer) / 10; - ffStrbufSubstrBefore(dir, dirLength); } } @@ -184,8 +142,6 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64); ffStrbufAppendS(&baseDir, "/sys/class/power_supply/"); - uint32_t baseDirLength = baseDir.length; - FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars); if(dirp == NULL) return "opendir(\"/sys/class/power_supply/\") == NULL"; @@ -196,9 +152,8 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) if(ffStrEquals(entry->d_name, ".") || ffStrEquals(entry->d_name, "..")) continue; - ffStrbufAppendS(&baseDir, entry->d_name); - parseBattery(&baseDir, entry->d_name, options, results); - ffStrbufSubstrBefore(&baseDir, baseDirLength); + FF_AUTO_CLOSE_FD int dfd = openat(dirfd(dirp), entry->d_name, O_RDONLY | O_CLOEXEC); + if (dfd > 0) parseBattery(dfd, entry->d_name, options, results); } return NULL;