Skip to content

Instantly share code, notes, and snippets.

@maxdeliso
Last active January 2, 2016 21:39
Show Gist options
  • Save maxdeliso/8364440 to your computer and use it in GitHub Desktop.
Save maxdeliso/8364440 to your computer and use it in GitHub Desktop.
battery checker C program vs bash script
/*
* asmBatt.c - stupid battery status printer
* Max DeLiso <[email protected]>
* license: don't pretend you wrote this or people will think you're friendless
*
* notes: this will only run on a 64 bit linux system, and only if ACPI
* is loaded and has populated the /sys/ entries listed below.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <asm/unistd_64.h>
#include <stdbool.h>
#include <stdint.h>
#define SYS_BLOCK_SIZE 16
#define STDOUT_FILENO 1
#define ENOW_PATH "/sys/class/power_supply/BAT0/energy_now"
#define EFULL_PATH "/sys/class/power_supply/BAT0/energy_full"
#define STATUS_PATH "/sys/class/power_supply/BAT0/status"
enum {
ERR_OPEN_FAILED = 1,
ERR_READ_FAILED,
ERR_WRITE_FAILED,
ERR_CLOSE_FAILED
};
static void readFile(const char * const filePath, char * buf);
static inline bool isNum(const char ch);
static uint64_t parseInteger(const char * const intString);
static uint64_t tenPow(const uint64_t exp);
static void writeBatt(const int battRemaining, const bool charging);
/* inline assembly syscall functions */
static void exit(const int errCode);
static int openRO(const char * const filePath);
static int close(const int fdHandle);
static int writeStdout(const char * const buf, const size_t len);
static ssize_t readSysBlock(const int fd, const char * buf);
extern void asmBatt() {
char enowStr[SYS_BLOCK_SIZE];
char efullStr[SYS_BLOCK_SIZE];
char statusStr[SYS_BLOCK_SIZE];
readFile(ENOW_PATH, enowStr);
readFile(EFULL_PATH, efullStr);
readFile(STATUS_PATH, statusStr);
const uint64_t battNow = parseInteger(enowStr);
const uint64_t battFull = parseInteger(efullStr);
const int battRemaining = (int) (100.0f * battNow / battFull);
writeBatt(battRemaining, statusStr[0] == 'C');
exit(0);
}
static void readFile(const char * const filePath, char * buf) {
int fd = openRO(filePath);
if(fd < 0) {
exit(ERR_OPEN_FAILED);
}
ssize_t bytesRead = readSysBlock(fd, buf);
if(bytesRead >= SYS_BLOCK_SIZE) {
exit(ERR_READ_FAILED);
}
buf[bytesRead] = '\0';
if(close(fd) < 0) {
exit(ERR_CLOSE_FAILED);
}
}
static inline bool isNum(const char ch) {
switch(ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return true;
default:
return false;
}
}
static uint64_t parseInteger(const char * const intString) {
uint64_t intValue = 0;
int intStringLen = 0;
while(isNum(intString[++intStringLen]));
for(int i = 0; i < intStringLen; ++i) {
intValue += (intString[i] - '0') * tenPow(intStringLen - i - 1);
}
return intValue;
}
static uint64_t tenPow(const uint64_t exp) {
if(exp == 0) return 1;
else return 10 * tenPow(exp - 1);
}
static void writeBatt(const int battRemaining, const bool charging) {
/* NOTE: this buffer is stored in global memory to prevent it from
* being bungled at high optimization levels */
static char outBuffer[7] = "XX% (X)";
/* |01 5 | */
/* |charged| */
if(battRemaining < 100) {
outBuffer[0] = '0' + (battRemaining / 10);
outBuffer[1] = '0' + (battRemaining % 10);
outBuffer[5] = (charging) ? ('+') : ('-');
} else {
outBuffer[0] = 'c';
outBuffer[1] = 'h';
outBuffer[2] = 'a';
outBuffer[3] = 'r';
outBuffer[4] = 'g';
outBuffer[5] = 'e';
outBuffer[6] = 'd';
}
if(writeStdout(outBuffer, 7) == -1) {
exit(ERR_WRITE_FAILED);
}
}
static void exit(const int errCode) {
__asm__("movq %0, %%rax\n\t"
"movq %1, %%rdi\n\t"
"syscall\n\t"
: /* no output */
:"r" ((uint64_t) __NR_exit),
"r" ((uint64_t) errCode)
:"rax", "rdi", "rcx", "r11");
}
static int openRO(const char * const filePath) {
uint64_t syscall_ret;
__asm__("movq %1, %%rax\n\t"
"movq %2, %%rdi\n\t"
"movq %3, %%rsi\n\t"
"movq %4, %%rdx\n\t"
"syscall\n\t"
"mov %%rax, %0\n\t"
:"=r" (syscall_ret)
:"r" ((uint64_t) __NR_open),
"r" (filePath),
"r" ((uint64_t) O_RDONLY),
"r" ((uint64_t) 0)
:"rax", "rdi", "rsi", "rdx", "rcx", "r11");
return syscall_ret;
}
static int close(const int fdHandle) {
uint64_t syscall_ret;
__asm__("movq %1, %%rax\n\t"
"movq %2, %%rdi\n\t"
"syscall\n\t"
"mov %%rax, %0\n\t"
:"=r" (syscall_ret)
:"r" ((uint64_t) __NR_close),
"r" ((uint64_t) fdHandle)
:"rax", "rdi", "rcx", "r11");
return syscall_ret;
}
static int writeStdout(const char * const buf, const size_t len) {
uint64_t syscall_ret;
__asm__("movq %1, %%rax\n\t"
"movq $1, %%rdi\n\t"
"movq %2, %%rsi\n\t"
"movq %3, %%rdx\n\t"
"syscall\n\t"
"mov %%rax, %0\n\t"
:"=r" (syscall_ret)
:"r" ((uint64_t) __NR_write),
"r" (buf),
"r" (len)
:"rax", "rdi", "rsi", "rdx", "rcx", "r11");
return syscall_ret;
}
static ssize_t readSysBlock(const int fd, const char * buf) {
uint64_t syscall_ret;
__asm__("movq %1, %%rax\n\t"
"movq %2, %%rdi\n\t"
"movq %3, %%rsi\n\t"
"movq %4, %%rdx\n\t"
"syscall\n\t"
"mov %%rax, %0\n\t"
:"=r" (syscall_ret)
:"r" ((uint64_t) __NR_read),
"r" ((uint64_t) fd),
"r" (buf),
"r" ((uint64_t) SYS_BLOCK_SIZE)
:"rax", "rdi", "rsi", "rdx", "rcx", "r11");
return syscall_ret;
}
#!/bin/bash
cat /sys/class/power_supply/BAT0/energy_now \
/sys/class/power_supply/BAT0/energy_full \
/sys/class/power_supply/BAT0/status |
tr "\n" " " |
awk '{printf("batt: %.2f%% %-13s", $1 / $2 * 100, $3)}'
CC=gcc
CFLAGS=-O3 -std=c99 -fno-builtin-exit
LDFLAGS=-static -nostartfiles -nodefaultlibs \
-Wl,--start-group -easmBatt -Wl,--end-group
STRIP=strip
OUT=asmBatt
$(OUT): $(OUT).c Makefile
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
$(STRIP) $(OUT)
clean:
$(RM) $(OUT)
@tiffanyng
Copy link

wuuuuuut !?? wut is dis?? what code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment