/* * This file is part of fwm-sysdaemon * get_powerstat.c - retrieve power status information from kernel * * Copyright (c) 2021, 2022 firk (firk@cantconnect.ru) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. * 4. Altered versions in any form must be plainly marked as such, and * must not be misinterpreted as being the original software. * * This software is provided by the author and contributors `as is' * without any express or implied warranty. */ #include #include #include #include #include #include #include #include #include "util.h" #include "get_powerstat.h" static void get_ac_stat(powerstat *r, int dd) { char tmp[30]; if(txtfile_read(dd, "online", tmp, sizeof(tmp), NULL)<0) r->get_ac_err = 1; else if(atoi(tmp)) r->is_ac_powered = 1; } static void get_bat_stat(powerstat *r, int dd) { int h1, h2; char tmp[30]; ull u; h1 = h2 = 0; if(txtfile_read(dd, "status", tmp, sizeof(tmp), NULL)<0) r->get_bat_err = 1; else { if(!strcmp(tmp,"Charging")) r->is_charging = 1; } if(txtfile_read(dd, "energy_now", tmp, sizeof(tmp), NULL)<0) r->get_bat_err = 1; else { if(!parse_ull(tmp, &u)) r->get_bat_err = 1; else { h1=1; r->charged = u; } } if(txtfile_read(dd, "energy_full", tmp, sizeof(tmp), NULL)<0) r->get_bat_err = 1; else { if(!parse_ull(tmp, &u)) r->get_bat_err = 1; else { h2=1; r->total = u; } } if(txtfile_read(dd, "capacity", tmp, sizeof(tmp), NULL)<0) r->get_bat_err = 1; else { if(!parse_ull(tmp, &u)) r->get_bat_err = 1; else r->charge_pctt = (u<=100)?(u*10):1000; } if(h1 && h2) { if(r->chargedtotal) r->charge_pctt = r->charged*1000 / r->total; else r->charge_pctt = 1000; } } extern int get_powerstat(powerstat * r, char const *batname, char const *acname) { int powfd, dd, e; DIR *dp; struct dirent * de; char type[30]; bzero(r, sizeof(*r)); r->is_ac_powered = 0; r->is_charging = 0; r->charge_pctt = -1; r->get_ac_err = -1; r->get_bat_err = -1; while((powfd = open("/sys/class/power_supply", O_DIRECTORY))<0) if(errno!=EINTR) return -1; if(acname) { if(!*acname) r->get_ac_err = 0; else if((dd = openat(powfd, acname, O_DIRECTORY))<0) r->get_ac_err = 1; else { r->get_ac_err = 0; get_ac_stat(r, dd); close(dd); } } if(batname) { if(!*batname) r->get_bat_err = 0; else if((dd = openat(powfd, batname, O_DIRECTORY))<0) r->get_bat_err = 1; else { r->get_bat_err = 0; strncpy(r->batname, batname, sizeof(r->batname)); get_bat_stat(r, dd); close(dd); } } if(acname && batname) { close(powfd); return 0; } if(!(dp = fdopendir(powfd))) { e=errno; close(powfd); errno=e; return -1; } while(errno=0, de=readdir(dp)) { if(*de->d_name=='.') continue; if((dd = openat(powfd, de->d_name, O_DIRECTORY))<0) continue; if(txtfile_read(dd, "type", type, sizeof(type), NULL)>=0) { if(!acname && !strcmp(type,"Mains")) { r->get_ac_err = 0; get_ac_stat(r, dd); } else if(!batname && !strcmp(type,"Battery")) { r->get_bat_err = 0; strncpy(r->batname, de->d_name, sizeof(r->batname)); get_bat_stat(r, dd); } } close(dd); } e = errno; closedir(dp); if(e) { errno = e; return -1; } return 0; }