From 782474b068948f42f8ac488aacf19d22a351bf92 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 11 Oct 2024 16:18:54 +0800 Subject: [PATCH] Battery (Linux): revert back not to use uevent Reading `uevent` is slow... --- src/detection/battery/battery_linux.c | 226 ++++++++++++++------------ 1 file changed, 118 insertions(+), 108 deletions(-) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 6ea2f42fe..006d7d6c2 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -6,152 +6,161 @@ // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power -static inline const char* findProperty(const char* buffer, ssize_t bufSize, const char* prefix) -{ - assert(bufSize > 0); - const char* p = memmem(buffer, (size_t) bufSize, prefix, strlen(prefix)); - if (p) return p + strlen(prefix); - return NULL; -} - static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* options, FFlist* results) { - ffStrbufAppendS(dir, "/uevent"); + uint32_t dirLength = dir->length; - char buffer[16 * 1024]; - ssize_t size = ffReadFileData(dir->chars, sizeof(buffer), buffer); - if (size <= 0) return; + FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate(); //type must exist and be "Battery" - const char* type = findProperty(buffer, size, "\nPOWER_SUPPLY_TYPE="); - if (type) - { - if (!ffStrStartsWith(type, "Battery\n")) return; - } - else if (!ffStrStartsWith(id, "BAT")) - { - char typeBuf[16] = {0}; - ffStrbufSubstrBefore(dir, dir->length - (uint32_t) strlen("uevent")); - ffStrbufAppendS(dir, "type"); - if (ffReadFileData(dir->chars, sizeof(typeBuf), typeBuf) < (ssize_t) strlen("Battery")) return; - if (!ffStrStartsWith(typeBuf, "Battery")) return; - } + ffStrbufAppendS(dir, "/type"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + ffStrbufTrimRightSpace(&tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Battery")) + return; //scope may not exist or must not be "Device" - const char* scope = findProperty(buffer, size, "\nPOWER_SUPPLY_SCOPE="); - if (scope && ffStrStartsWith(scope, "Device\n")) return; + ffStrbufAppendS(dir, "/scope"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + ffStrbufTrimRightSpace(&tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device")) + return; //capacity must exist and be not empty - const char* capacity = findProperty(buffer, size, "\nPOWER_SUPPLY_CAPACITY="); - if (!capacity) return; + ffStrbufAppendS(dir, "/capacity"); + bool available = ffReadFileBuffer(dir->chars, &tmpBuffer); // This is expensive in my laptop + ffStrbufSubstrBefore(dir, dirLength); + + if (!available) + return; + + FFBatteryResult* result = ffListAdd(results); + result->capacity = ffStrbufToDouble(&tmpBuffer); //At this point, we have a battery. Try to get as much values as possible. - FFBatteryResult* result = ffListAdd(results); - result->capacity = strtod(capacity, NULL); - ffStrbufInit(&result->manufacturer); - const char* manufacturer = findProperty(buffer, size, "\nPOWER_SUPPLY_MANUFACTURER="); - if (manufacturer) - ffStrbufAppendSUntilC(&result->manufacturer, manufacturer, '\n'); + ffStrbufAppendS(dir, "/manufacturer"); + if (ffReadFileBuffer(dir->chars, &result->manufacturer)) + ffStrbufTrimRightSpace(&result->manufacturer); else if (ffStrEquals(id, "macsmc-battery")) // asahi ffStrbufSetStatic(&result->manufacturer, "Apple Inc."); + ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->modelName); - ffStrbufAppendSUntilC(&result->modelName, findProperty(buffer, size, "\nPOWER_SUPPLY_MODEL_NAME="), '\n'); + ffStrbufAppendS(dir, "/model_name"); + if (ffReadFileBuffer(dir->chars, &result->modelName)) + ffStrbufTrimRightSpace(&result->modelName); + ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->technology); - const char* technology = findProperty(buffer, size, "\nPOWER_SUPPLY_TECHNOLOGY="); - if (technology && !ffStrStartsWith(technology, "Unknown")) - ffStrbufAppendSUntilC(&result->technology, technology, '\n'); + ffStrbufAppendS(dir, "/technology"); + if (ffReadFileBuffer(dir->chars, &result->technology)) + ffStrbufTrimRightSpace(&result->technology); + ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->status); - const char* status = findProperty(buffer, size, "\nPOWER_SUPPLY_STATUS="); - if (status) - { - // Unknown, Charging, Discharging, Not charging, Full - if (ffStrStartsWith(status, "Not charging\n") || ffStrStartsWith(status, "Full\n")) - ffStrbufSetStatic(&result->status, "AC Connected"); - else if (ffStrStartsWith(status, "Charging\n")) - ffStrbufSetStatic(&result->status, "AC Connected, Charging"); - else if (ffStrStartsWith(status, "Discharging\n")) - ffStrbufSetStatic(&result->status, "Discharging"); - } + ffStrbufAppendS(dir, "/status"); + if (ffReadFileBuffer(dir->chars, &result->status)) + ffStrbufTrimRightSpace(&result->status); + ffStrbufSubstrBefore(dir, dirLength); - const char* capacityLevel = findProperty(buffer, size, "\nPOWER_SUPPLY_CAPACITY_LEVEL="); - if (capacityLevel && ffStrStartsWith(capacityLevel, "Critical\n")) - { - if (result->status.length) - ffStrbufAppendS(&result->status, ", Critical"); - else - ffStrbufSetStatic(&result->status, "Critical"); - } - - ffStrbufInit(&result->serial); - ffStrbufAppendSUntilC(&result->serial, findProperty(buffer, size, "\nPOWER_SUPPLY_SERIAL_NUMBER="), '\n'); - - ffStrbufAppendS(dir, "/cycle_count"); - const char* cycleCountStr = findProperty(buffer, size, "\nPOWER_SUPPLY_CYCLE_COUNT="); - if (cycleCountStr) - { - int64_t cycleCount = strtol(cycleCountStr, NULL, 10); - result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount; - } + // Unknown, Charging, Discharging, Not charging, Full result->timeRemaining = -1; - const char* timeToEmptyStr = findProperty(buffer, size, "\nPOWER_SUPPLY_TIME_TO_EMPTY_NOW="); - if (timeToEmptyStr) + if (ffStrbufEqualS(&result->status, "Discharging")) { - int64_t value = strtol(timeToEmptyStr, NULL, 0); - if (value > 0) - result->timeRemaining = (int32_t) value; + ffStrbufAppendS(dir, "/time_to_empty_now"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) + result->timeRemaining = (int32_t) ffStrbufToSInt(&tmpBuffer, 0); else { - const char* timeToFullStr = findProperty(buffer, size, "\nPOWER_SUPPLY_TIME_TO_FULL_NOW="); - if (timeToFullStr) + ffStrbufAppendS(dir, "/charge_now"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) { - value = strtol(timeToFullStr, NULL, 0); - if (value > 0) - result->timeRemaining = (int32_t) value; - } - } - } - else if (ffStrStartsWith(status, "Discharging\n")) - { - const char* chargeNow = findProperty(buffer, size, "\nPOWER_SUPPLY_CHARGE_NOW="); - if (chargeNow) - { - int64_t charge = strtol(chargeNow, NULL, 0); - if (charge > 0) - { - const char* currentNow = findProperty(buffer, size, "\nPOWER_SUPPLY_CURRENT_NOW="); - if (currentNow) + int64_t chargeNow = ffStrbufToSInt(&tmpBuffer, 0); + if (chargeNow > 0) { - int64_t current = strtol(currentNow, NULL, 0); - if (current > 0) - result->timeRemaining = (int32_t) (charge * 3600 / current); + ffStrbufAppendS(dir, "/current_now"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) + { + int64_t currentNow = ffStrbufToSInt(&tmpBuffer, INT64_MIN); + if (currentNow < 0) currentNow = -currentNow; + if (currentNow > 0) + result->timeRemaining = (int32_t) ((chargeNow * 3600) / currentNow); + } } } } } - ffStrbufInit(&result->manufactureDate); - const char* myear = findProperty(buffer, size, "\nPOWER_SUPPLY_MANUFACTURE_YEAR="); - if (myear) + if (ffStrbufEqualS(&result->status, "Not charging") || ffStrbufEqualS(&result->status, "Full")) + ffStrbufSetStatic(&result->status, "AC Connected"); + else if (ffStrbufEqualS(&result->status, "Unknown")) + ffStrbufClear(&result->status); + + ffStrbufAppendS(dir, "/capacity_level"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) { - int year = (int) strtol(myear, NULL, 10); + ffStrbufTrimRightSpace(&result->manufacturer); + if (ffStrbufEqualS(&tmpBuffer, "Critical")) + { + if (result->status.length) + ffStrbufAppendS(&result->status, ", Critical"); + else + ffStrbufSetStatic(&result->status, "Critical"); + } + } + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->serial); + ffStrbufAppendS(dir, "/serial_number"); + if (ffReadFileBuffer(dir->chars, &result->serial)) + ffStrbufTrimRightSpace(&result->serial); + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufAppendS(dir, "/cycle_count"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) + { + 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) + { + int year = (int) ffStrbufToSInt(&tmpBuffer, 0); if (year > 0) { - const char* mmonth = findProperty(buffer, size, "\nPOWER_SUPPLY_MANUFACTURE_MONTH="); - if (mmonth) + ffStrbufAppendS(dir, "/manufacture_month"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) { - int month = (int) strtol(mmonth, NULL, 10); + int month = (int) ffStrbufToSInt(&tmpBuffer, 0); if (month > 0) { - const char* mday = findProperty(buffer, size, "\nPOWER_SUPPLY_MANUFACTURE_DAY="); - if (mday) + ffStrbufAppendS(dir, "/manufacture_day"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) { - int day = (int) strtol(mday, NULL, 0); + int day = (int) ffStrbufToSInt(&tmpBuffer, 0); if (day > 0) ffStrbufSetF(&result->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); } @@ -163,9 +172,10 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option result->temperature = FF_BATTERY_TEMP_UNSET; if (options->temp) { - const char* tempStr = findProperty(buffer, size, "\nPOWER_SUPPLY_TEMP="); - if (tempStr) - result->temperature = strtod(tempStr, NULL) / 10.; + ffStrbufAppendS(dir, "/temp"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + result->temperature = ffStrbufToDouble(&tmpBuffer) / 10; + ffStrbufSubstrBefore(dir, dirLength); } }