/* $Id: libacpi.c 1974 2006-09-06 09:50:27Z nick $
 *
 * Copyright (c) 2002 Costantino Pistagna <valvoline@vrlteam.org>
 * Copyright (c) 2003 Noberasco Michele <2001s098@educ.disi.unige.it>
 * Copyright (c) 2003 Edscott Wilson Garcia <edscott@imp.mx>
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library General Public License as published
 * by the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef __libacpi_c__
#define __libacpi_c__
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>

#if HAVE_SYSCTL

#ifdef __NetBSD__
#include <sys/param.h>
/* CTLTYPE does not exist in NetBSD headers.
 * Defining it to 0x0f here won't do any harm though. */
#define CTLTYPE 0x0f
#endif

#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>

#endif

#include "libacpi.h"

#define ACBASE "/proc/acpi/ac_adapter"


static char batteries[MAXBATT][128];
static char battinfo[MAXBATT][128];
#ifndef __linux__
#if HAVE_SYSCTL
 static int
name2oid(char *name, int *oidp)
{
	int oid[2];
	int i;
	size_t j;

	oid[0] = 0;
	oid[1] = 3;

	j = CTL_MAXNAME * sizeof(int);
	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
	if (i < 0)
		return i;
	j /= sizeof(int);
	return (j);
}
static int
oidfmt(int *oid, int len, char *fmt, u_int *kind)
{
	int qoid[CTL_MAXNAME+2];
	u_char buf[BUFSIZ];
	int i;
	size_t j;

	qoid[0] = 0;
	qoid[1] = 4;
	memcpy(qoid + 2, oid, len * sizeof(int));

	j = sizeof(buf);
	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
	if (i)
		err(1, "sysctl fmt %d %d %d", i, j, errno);

	if (kind)
		*kind = *(u_int *)buf;

	if (fmt)
		strcpy(fmt, (char *)(buf + sizeof(u_int)));
	return 0;
}



static int
get_var(int *oid, int nlen)
{
		int retval=0;
	u_char buf[BUFSIZ], *val, *p;
	char name[BUFSIZ], *fmt, *sep;
	int qoid[CTL_MAXNAME+2];
	int i;
	size_t j, len;
	u_int kind;
/*	int (*func)(int, void *);*/

	qoid[0] = 0;
	memcpy(qoid + 2, oid, nlen * sizeof(int));

	qoid[1] = 1;
	j = sizeof(name);
	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
	if (i || !j)
		err(1, "sysctl name %d %d %d", i, j, errno);

	sep = "=";


	/* find an estimate of how much we need for this var */
	j = 0;
	i = sysctl(oid, nlen, 0, &j, 0, 0);
	j += j; /* we want to be sure :-) */

	val = alloca(j + 1);
	len = j;
	i = sysctl(oid, nlen, val, &len, 0, 0);
	if (i || !len)
		return (1);

	val[len] = '\0';
	fmt = buf;
	oidfmt(oid, nlen, fmt, &kind);
	p = val;
	switch (*fmt) {
	case 'I':
#ifdef DEBUG
		printf("I:%s%s", name, sep);
#endif
		fmt++;
		val = "";
		while (len >= sizeof(int)) {
			if(*fmt == 'U'){
				retval=*((unsigned int *)p);
#ifdef DEBUG
				printf("x%s%u", val, *(unsigned int *)p);
#endif
			}
			else {
				retval=*((int *)p);
#ifdef DEBUG
				printf("x%s%d", val, *(int *)p);
#endif
			}
			val = " ";
			len -= sizeof(int);
			p += sizeof(int);
		}

		return (retval);
	default:
			printf("%s%s", name, sep);
		printf("Format:%s Length:%d Dump:0x", fmt, len);
		while (len-- && (p < val + 16))
			printf("%02x", *p++);
		if (len > 16)
			printf("...");
		return (0);
	}
	return (0);
}


#endif
#endif

/* see if we have ACPI support */
int check_acpi(void)
{
  DIR *battdir;
  struct dirent *batt;
  char *name;
#ifdef __linux__
  FILE *acpi;

  if (!(acpi = fopen ("/proc/acpi/info", "r")))
  {
#ifdef DEBUG
	  printf("DBG:no acpi: /proc/acpi/info not found!\n");
#endif
    return 1;
  }

  /* yep, all good */
  fclose (acpi);

  /* now enumerate batteries */
  batt_count = 0;
  battdir = opendir ("/proc/acpi/battery");
  if (battdir == 0)
  {
#ifdef DEBUG
	  printf("DBG:No battery. /proc/acpi/battery not found!\n");
#endif
    return 2;
  }
  while ((batt = readdir (battdir)))
  {
    name = batt->d_name;

    /* skip . and .. */
    if (!strncmp (".", name, 1) || !strncmp ("..", name, 2)) continue;

    sprintf (batteries[batt_count], "/proc/acpi/battery/%s/state", name);
    if (!(acpi = fopen (batteries[batt_count], "r"))) {
       sprintf (batteries[batt_count], "/proc/acpi/battery/%s/status", name);
    }
    else fclose (acpi);

    sprintf (battinfo[batt_count], "/proc/acpi/battery/%s/info", name);
#ifdef DEBUG
	  printf("DBG:battery number %d at:\n",batt_count);
	  printf("DBG:info->%s\n",battinfo[batt_count]);
	  printf("DBG:state->%s\n",batteries[batt_count]);
	  printf("DBG:------------------------\n");
#endif

    batt_count++;
  }
  closedir (battdir);
  return 0;
#else
#ifdef HAVE_SYSCTL
  {
    static char buf[BUFSIZ];
    char *bufp=buf;
    char fmt[BUFSIZ];
    void *oldp=(void *)buf;
    size_t oldlenp=BUFSIZ;
    int len,mib[CTL_MAXNAME];
    u_int kind;
/*  snprintf(buf, BUFSIZ, "%s", "hw.acpi.battery.time");*/
    snprintf(buf, BUFSIZ, "%s", "hw.acpi.battery.units");
    len = name2oid(bufp, mib);
    if (len <=0) return 1;
    if (oidfmt(mib, len, fmt, &kind)) return 1;
    if ((kind & CTLTYPE) == CTLTYPE_NODE) return 1;
    batt_count=get_var(mib, len);

  }
  return 0;
#else
  return 1;
#endif
#endif
}

int read_acad_state(void)
{
#ifdef __linux__
  FILE *acpi;
  char *ptr;
  char stat;

  char acpath[64];
  char *name;
  DIR  *acdir;
  struct dirent *ac;

  if (!(acdir=opendir(ACBASE))){
    return -1;
  }
  while ((ac = readdir (acdir))){
    name = ac->d_name;

    /* skip . and .. */
    if (name[0] == '.')
      continue;

    sprintf (acpath, "%s/%s/state", ACBASE, name);
    if (access(acpath,R_OK)){
      sprintf (acpath, "%s/%s/status", ACBASE, name);
      if (access(acpath,R_OK)){
	return -1;
      }
    }
    break; //only one ac adapter supported
  }
  closedir(acdir);
  acpi = fopen (acpath, "r");

  fread (buf, 512, 1, acpi);
  fclose (acpi);
  if (!acadstate) acadstate=(ACADstate *)malloc(sizeof(ACADstate));

  if ( (ptr = strstr(buf, "state:")) )
  {
    stat = *(ptr + 26);
    if (stat == 'n') acadstate->state = 1;
    if (stat == 'f')
  	{
	    acadstate->state = 0;
	    return 0;
  	}
  }

  if ( (ptr = strstr (buf, "Status:")) )
  {
    stat = *(ptr + 26);
    if (stat == 'n') acadstate->state = 1;
    if (stat == 'f')
  	{
	    acadstate->state = 0;
	    return 0;
	  }
  }

  return 1;
#else
#ifdef HAVE_SYSCTL
  static char buf[BUFSIZ];
  char fmt[BUFSIZ];
  void *oldp=(void *)buf;
  char *bufp=buf;
  size_t oldlenp=BUFSIZ;
  int len,mib[CTL_MAXNAME];
  u_int kind;
  int retval;
  snprintf(buf, BUFSIZ, "%s", "hw.acpi.acline");
  len = name2oid(bufp, mib);
  if (len <= 0) return(-1);
  if (oidfmt(mib, len, fmt, &kind))
	err(1, "couldn't find format of oid '%s'", bufp);
  if (len < 0) errx(1, "unknown oid '%s'", bufp);
  if ((kind & CTLTYPE) == CTLTYPE_NODE) {
	printf("oh-oh...\n");
  } else {
	retval=get_var(mib, len);
#ifdef DEBUG
	printf("retval=%d\n",retval);
#endif
  }
  return retval;
#else
  return 0;
#endif
#endif
}

int read_acpi_info(int battery)
{
#ifdef __linux__
  FILE *acpi;
  char *ptr;
  char stat;
  int temp;

  if (battery > MAXBATT) {
#ifdef DEBUG
	  printf("DBG: error, battery > MAXBATT (%d)\n",MAXBATT);
#endif
	  return 0;
  }
  if (!(acpi = fopen (battinfo[battery], "r"))) {
#ifdef DEBUG
	  printf("DBG:cannot open %s for read!\n",battinfo[battery]);
#endif
	  return 0;
  }

#ifdef DEBUG
  {
	  int jj= fread (buf, 1,512, acpi);
	  printf("DBG:%d characters read from %s\n",jj,battinfo[battery]);
  }
#else
  fread (buf, 1,512, acpi);
#endif
  fclose (acpi);

  if (!acpiinfo) acpiinfo=(ACPIinfo *)malloc(sizeof(ACPIinfo));

  if ((ptr = strstr (buf, "present:")) || (ptr = strstr (buf, "Present:")))
  {
#ifdef DEBUG
	  printf("DBG:Battery present... and its called %s\n",battinfo[battery]);
#endif
    stat = *(ptr + 25);
    if (stat == 'y')
  	{
	    acpiinfo->present = 1;
  	  if ((ptr = strstr (buf, "design capacity:")) || (ptr = strstr (buf, "Design Capacity:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &temp);
	      acpiinfo->design_capacity = temp;
#ifdef DEBUG
	  printf("DBG:design capacity:%d\n",temp);
#endif
	    }
	    if ((ptr = strstr (buf, "last full capacity:")) || (ptr = strstr (buf, "Last Full Capacity:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &temp);
	      acpiinfo->last_full_capacity = temp;
#ifdef DEBUG
	  printf("DBG:last full capacity:%d\n",temp);
#endif
	    }
	    if ((ptr = strstr (buf, "battery technology:")) || (ptr = strstr (buf, "Battery Technology:")))
	    {
	      stat = *(ptr + 25);
	      switch (stat)
		    {
		      case 'n':
		        acpiinfo->battery_technology = 1;
		        break;
		      case 'r':
		        acpiinfo->battery_technology = 0;
		        break;
		    }
	    }
	    if ((ptr = strstr (buf, "design voltage:")) || (ptr = strstr (buf, "Design Voltage:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &temp);
	      acpiinfo->design_voltage = temp;
#ifdef DEBUG
	  printf("DBG:design voltage:%d\n",temp);
#endif
	    }
	    if ((ptr = strstr (buf, "design capacity warning:")) || (ptr = strstr (buf, "Design Capacity Warning:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &temp);
	      acpiinfo->design_capacity_warning = temp;
#ifdef DEBUG
	  printf("DBG:design capacity warning:%d\n",temp);
#endif
	    }
  	  if ((ptr = strstr (buf, "design capacity low:")) || (ptr = strstr (buf, "Design Capacity Low:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &temp);
	      acpiinfo->design_capacity_low = temp;
#ifdef DEBUG
	  printf("DBG:design capacity low:%d\n",temp);
#endif
	    }
#ifdef DEBUG
	  printf("DBG:ALL Battery information read...\n");
#endif
	  }
    else /* Battery not present */
	  {
#ifdef DEBUG
	  printf("DBG:Battery not present!... and its called %s\n",battinfo[battery]);
#endif
	    acpiinfo->present = 0;
	    acpiinfo->design_capacity = 0;
	    acpiinfo->last_full_capacity = 0;
	    acpiinfo->battery_technology = 0;
	    acpiinfo->design_voltage = 0;
	    acpiinfo->design_capacity_warning = 0;
	    acpiinfo->design_capacity_low = 0;
	    return 0;
	  }
  }

  return 1;
#else
#ifdef HAVE_SYSCTL
  static char buf[BUFSIZ];
  char *bufp=buf;
  int len,mib[CTL_MAXNAME];
  char fmt[BUFSIZ];
  u_int kind;
  int retval;
  if (!acpiinfo) acpiinfo=(ACPIinfo *)malloc(sizeof(ACPIinfo));
	    acpiinfo->present = 0;
	    acpiinfo->design_capacity = 0;
	    acpiinfo->last_full_capacity = 0;
	    acpiinfo->battery_technology = 0;
	    acpiinfo->design_voltage = 0;
	    acpiinfo->design_capacity_warning = 0;
	    acpiinfo->design_capacity_low = 0;
  snprintf(buf, BUFSIZ, "%s", "hw.acpi.battery.units");
  len = name2oid(bufp, mib);
  if (len <= 0) return(-1);
  if (oidfmt(mib, len, fmt, &kind))
	err(1, "couldn't find format of oid '%s'", bufp);
  if (len < 0) errx(1, "unknown oid '%s'", bufp);
  if ((kind & CTLTYPE) == CTLTYPE_NODE) {
	printf("oh-oh...\n");
  } else {
	retval=get_var(mib, len);
#ifdef DEBUG
	printf("retval=%d\n",retval);
#endif
  }
  acpiinfo->present = retval;
  return 1;
#else
  return 0;
#endif
#endif

}

int read_acpi_state(int battery)
{
#ifdef __linux__
  FILE *acpi;
  char *ptr;
  char stat;

  int percent = 100;		/* battery percentage */
  int ptemp, rate, rtime = 0;

  if (!(acpi = fopen (batteries[battery], "r"))) {
#ifdef DEBUG
	  printf("DBG:Could not open %s (%d)\n",batteries[battery],battery);
#endif
	  return 0;
  }

  fread (buf, 512, 1, acpi);
  fclose (acpi);
  if (!acpistate) acpistate=(ACPIstate *)malloc(sizeof(ACPIstate));

  if ((ptr = strstr (buf, "present:")) || (ptr = strstr (buf, "Present:")))
  {
#ifdef DEBUG
	  printf("DBG:Battery state present...\n");
#endif
    stat = *(ptr + 25);
    if (stat == 'y')
  	{
	    acpistate->present = 1;
	    if ((ptr = strstr (buf, "charging state:")) || (ptr = strstr (buf, "State:")))
	    {
	      stat = *(ptr + 25);
	      switch (stat)
		    {
		      case 'd':
		        acpistate->state = 1;
		        break;
		      case 'c':
		        if (*(ptr + 33) == '/')
		          acpistate->state = 0;
		        else
		          acpistate->state = 2;
		        break;
		      case 'u':
		        acpistate->state = 3;
		        break;
		    }
	    }
	    /* This section of the code will calculate "percentage remaining"
	     * using battery capacity, and the following formula
	     * (acpi spec 3.9.2):
	     *
	     * percentage = (current_capacity / last_full_capacity) * 100;
	     *
	     */
	    if ((ptr = strstr (buf, "remaining capacity:")) || (ptr = strstr (buf, "Remaining Capacity:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &ptemp);
	      acpistate->rcapacity = ptemp;
	      percent =	(float) ((float) ptemp / (float) acpiinfo->last_full_capacity) * 100;
	      acpistate->percentage = percent;
#ifdef DEBUG
	  printf("DBG:remaining capacity:100 * %d/%d = %d\n",
			  ptemp,acpiinfo->last_full_capacity,acpistate->percentage);
#endif
	    }
	    if ((ptr = strstr (buf, "present rate:")) || (ptr = strstr (buf, "Present Rate:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &rate);

	      /* if something wrong */
	      if (rate <= 0) rate = 0;

	      acpistate->prate = rate;

	      /* time remaining in minutes */
	      rtime = ((float) ((float) acpistate->rcapacity /
				(float) acpistate->prate)) * 60;
	      if (rtime <= 0) rtime = 0;

				acpistate->rtime = rtime;
	    }
	    if ((ptr = strstr (buf, "present voltage:")) || (ptr = strstr (buf, "Battery Voltage:")))
	    {
	      ptr += 25;
	      sscanf (ptr, "%d", &ptemp);
	      acpistate->pvoltage = ptemp;
	    }
	  }
    else /* Battery not present */
	  {
	    acpistate->present = 0;
	    acpistate->state = UNKNOW;
	    acpistate->prate = 0;
	    acpistate->rcapacity = 0;
	    acpistate->pvoltage = 0;
	    acpistate->rtime = 0;
	    acpistate->percentage = 0;
	    return 0;
	  }
  }

  return 1;
#else
#ifdef HAVE_SYSCTL
  char *string;
  static char buf[BUFSIZ];
  char fmt[BUFSIZ];
  char *bufp=buf;
  void *oldp=(void *)buf;
  size_t oldlenp=BUFSIZ;
  int len,mib[CTL_MAXNAME];
  int retval;
  u_int kind;
  if (!acpistate) acpistate=(ACPIstate *)malloc(sizeof(ACPIstate));
  acpistate->present = 0;
  acpistate->state = UNKNOW;
  acpistate->prate = 0;
  acpistate->rcapacity = 0;
  acpistate->pvoltage = 0;
  acpistate->rtime = 0;
  acpistate->percentage = 0;

  snprintf(buf, BUFSIZ, "%s", "hw.acpi.battery.time");
  len = name2oid(bufp, mib);
  if (len <= 0) return(-1);
  if (oidfmt(mib, len, fmt, &kind))
	err(1, "couldn't find format of oid '%s'", bufp);
  if (len < 0) errx(1, "unknown oid '%s'", bufp);
  if ((kind & CTLTYPE) == CTLTYPE_NODE) {
	printf("oh-oh...\n");
  } else {
	retval=get_var(mib, len);
#ifdef DEBUG
	printf("retval=%d\n",retval);
#endif
  }
  acpistate->rtime =(retval<0)?0:retval;

  snprintf(buf, BUFSIZ, "%s", "hw.acpi.battery.life");
  len = name2oid(bufp, mib);
  if (len <= 0) return(-1);
  if (oidfmt(mib, len, fmt, &kind))
	err(1, "couldn't find format of oid '%s'", bufp);
  if (len < 0) errx(1, "unknown oid '%s'", bufp);
  if ((kind & CTLTYPE) == CTLTYPE_NODE) {
	printf("oh-oh...\n");
  } else {
	retval=get_var(mib, len);
#ifdef DEBUG
	printf("retval=%d\n",retval);
#endif
  }
  acpistate->percentage =retval;
  return 1;
#else
  return 0;
#endif
#endif
}

int get_fan_status(void)
{
  FILE *fp;
  char * proc_fan_status="/proc/acpi/toshiba/fan";
  char line[256];
  /*int result;*/

   /* Check for fan status in PROC filesystem */
    if ( (fp=fopen(proc_fan_status, "r")) != NULL ) {
 	  fgets(line,255,fp);
  	  fclose(fp);
  	  if (strlen(line) && strstr(line,"1")) return 1;
    	  else return 0;
    }
    proc_fan_status="/proc/acpi/fan/*/state";
    if ( (fp=fopen(proc_fan_status, "r")) == NULL ) return 0;

    fgets(line,255,fp);
    fclose(fp);

    if (strlen(line) && strstr(line,"off")) return 0;
    else return 1;
}

const char *get_temperature(void)
{
#ifdef __linux__
  FILE *fp;
  char *proc_temperature="/proc/acpi/thermal_zone/*0/temperature";
  static char *p,line[256];

  if ( (fp=fopen(proc_temperature, "r")) == NULL) return NULL;
  fgets(line,255,fp);
  fclose(fp);
  p=strtok(line," ");
  if (!p) return NULL;
  p=p+strlen(p)+1;
  while (p && *p ==' ') p++;
  if (*p==0) return NULL;
  if (strchr(p,'\n')) p=strtok(p,"\n");
  return (const char *)p;
#else
#ifdef HAVE_SYSCTL
  static char buf[BUFSIZ];
  char fmt[BUFSIZ];
  char *bufp=buf;
  void *oldp=(void *)buf;
  size_t oldlenp=BUFSIZ;
  int len,mib[CTL_MAXNAME];
  int retval;
  u_int kind;
  snprintf(buf, BUFSIZ, "%s", "hw.acpi.thermal.tz0.temperature");
  len = name2oid(bufp, mib);
  if (len <= 0) return(NULL);
  if (oidfmt(mib, len, fmt, &kind))
	err(1, "couldn't find format of oid '%s'", bufp);
  if (len < 0) errx(1, "unknown oid '%s'", bufp);
  if ((kind & CTLTYPE) == CTLTYPE_NODE) {
	printf("oh-oh...\n");
  } else {
	retval=get_var(mib, len);
#ifdef DEBUG
	printf("retval=%d\n",retval);
#endif
  }
  snprintf(buf, BUFSIZ, "%d C",(retval-2735)/10);
  return (const char *)buf;
#else
  return "";
#endif
#endif
}



syntax highlighted by Code2HTML, v. 0.9.1