#include "e.h"
#include "e_mod_main.h"

#if defined (__FreeBSD__) || defined(__DragonFly__)
# include <sys/types.h>
# include <sys/sysctl.h>
# include <errno.h>
#elif defined (__OpenBSD__)
# include <sys/param.h>
# include <sys/sysctl.h>
# include <sys/sensors.h>
# include <errno.h>
# include <err.h>
#else
// https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
typedef enum
{
   TEMP_UNKNOWN,
   TEMP_CPU, // CPU embedded diode
   TEMP_TRANSISTOR, // 3904 transistor
   TEMP_THERMAL, // thermal diode
   TEMP_THERMISTOR, // thermistor
   TEMP_AMD_AMDSI, // AMD AMDSI
   TEMP_INTEL_PECI // Intel PECI
} Temp_Type;

typedef enum
{
   PWM_OFF, // full speed
   PWM_ON, // enabled
   PWM_AUTO // automatic mode
} Pwm_Mode;

typedef struct
{
   Temp_Type type;
   const char *path;
   const char *name;
   const char *label;
   int enable;
   int fault;
   double temp;
   double min;
   double max;
   double crit;
   double emergency;
   double offset;
} Temp;

typedef struct
{
   const char *path;
   const char *name;
   const char *label;
   int enable;
   int fault;
   int rpm;
   int min;
   int max;
   int target;
} Fan;

typedef struct
{
   const char *path;
   const char *name;
   Pwm_Mode mode;
   double val;
   double min;
   double max;
} Pwm;

typedef struct
{
   const char *path;
   const char *name;
   const char *label;
   double mhz;
} Freq;

typedef struct
{
   const char *path;
   const char *name;
   int enable;
   double watts;
   double min;
   double max;
   double cap;
   double cap_min;
   double cap_max;
   double crit;
} Power;

typedef struct
{
   const char *path;
   const char *name;
   const char *label;
   int enable;
   double volts;
   double min;
   double max;
   double crit_min;
   double crit;
} Volt;

typedef struct
{
   const char *path;
   const char *name;
   int enable;
   double amps;
   double min;
   double max;
   double crit_min;
   double crit;
} Amp;

typedef struct
{
   const char *path;
   const char *name;
   int enable;
   double joules;
} Energy;

typedef struct
{
   const char *path;
   const char *name;
   int enable;
   double percent;
} Humid;

typedef struct
{
   const char *path;
   const char *name;
   int alarm;
} Intrusion;

typedef struct
{
   const char *path;
   const char *name;
   const char *label;
   Eina_List *temps;
   Eina_List *fans;
   Eina_List *pwms;
   Eina_List *freqs;
   Eina_List *powers;
   Eina_List *volts;
   Eina_List *amps;
   Eina_List *energies;
   Eina_List *humids;
   Eina_List *intrusions;
} Mon;

static Eina_Lock mons_lock;
static Eina_List *mons = NULL;

static char *
_file_str_get(const char *path)
{
   int fd = open(path, O_RDONLY);
   char buf[4096], *str = NULL, *s;
   ssize_t sz;

   if (fd < 0) return NULL;
   sz = read(fd, buf, sizeof(buf) - 1);
   if (sz < 1) goto err;
   buf[sz] = '\0';
   for (s = buf; s[0] != '\0'; s++)
     {
        if ((s[0] == '\n') || (s[0] == '\r'))
          {
             s[0] = '\0';
             break;
          }
     }
   str = strdup(buf);
err:
   close(fd);
   return str;
}

#define NOVAL -999999999

static int
_file_int_get(const char *path)
{
   char *str = _file_str_get(path);
   if (!str) return NOVAL;
   int val = atoi(str);
   free(str);
   return val;
}

#define GETVAL_STR(_base, _name, _field) do { char *_s; char _b[1024 + 512]; \
   snprintf(_b, sizeof(_b), "%s_%s", _base, _name); \
   if ((_s = _file_str_get(_b))) { \
      _field = eina_stringshare_add(_s); \
      free(_s); \
   } \
} while (0)
#define GETVAL_INT(_base, _name, _field) do { int _v; char _b[1024 + 512]; \
   snprintf(_b, sizeof(_b), "%s_%s", _base, _name); \
   if ((_v = _file_int_get(_b)) >= 0) _field = _v; \
} while (0)
#define GETVAL_DBL(_base, _name, _field, _div) do { int _v; char _b[1024 + 512]; \
   snprintf(_b, sizeof(_b), "%s_%s", _base, _name); \
   if ((_v = _file_int_get(_b)) >= 0) _field = (double)_v / (_div); \
} while (0)

static void
_hwmon_init(void)
{
   Eina_List *list;
   char *s, *str, buf[1024], buf2[1024 + 256];
   int i, x;

   eina_lock_take(&mons_lock);
   list = ecore_file_ls("/sys/class/hwmon");
   EINA_LIST_FREE(list, s)
     {
        Mon *mon = calloc(1, sizeof(Mon));
        if (mon)
          {
             snprintf(buf, sizeof(buf), "/sys/class/hwmon/%s", s);
             mon->path = eina_stringshare_add(buf);
             mon->name = eina_stringshare_add(s);
             snprintf(buf, sizeof(buf), "/sys/class/hwmon/%s/name", s);
             str = _file_str_get(buf);
             if (str)
               {
                  mon->label = eina_stringshare_add(str);
                  free(str);
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/temp%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x == NOVAL) break;
                  Temp *t = calloc(1, sizeof(Temp));
                  if (t)
                    {
                       t->temp = (double)x / 1000.0;
                       t->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "temp%i", i);
                       t->name = eina_stringshare_add(buf2);
                       GETVAL_STR(buf, "label", t->label);
                       t->enable = 1;
                       GETVAL_INT(buf, "enable", t->enable);
                       GETVAL_INT(buf, "fault", t->fault);
                       GETVAL_INT(buf, "type", t->type);
                       GETVAL_DBL(buf, "min", t->min, 1000.0);
                       GETVAL_DBL(buf, "max", t->max, 1000.0);
                       GETVAL_DBL(buf, "crit", t->crit, 1000.0);
                       GETVAL_DBL(buf, "emergency", t->emergency, 1000.0);
                       mon->temps = eina_list_append(mon->temps, t);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/fan%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x == NOVAL) break;
                  Fan *f = calloc(1, sizeof(Fan));
                  if (f)
                    {
                       f->rpm = x;
                       f->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "fan%i", i);
                       f->name = eina_stringshare_add(buf2);
                       GETVAL_STR(buf, "label", f->label);
                       f->enable = 1;
                       GETVAL_INT(buf, "enable", f->enable);
                       GETVAL_INT(buf, "fault", f->fault);
                       GETVAL_INT(buf, "min", f->min);
                       GETVAL_INT(buf, "max", f->max);
                       GETVAL_INT(buf, "target", f->target);
                       mon->fans = eina_list_append(mon->fans, f);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/pwm%i", s, i);
                  x = _file_int_get(buf);
                  if (x == NOVAL) break;
                  Pwm *p = calloc(1, sizeof(Pwm));
                  if (p)
                    {
                       p->val = (double)x / 255.0;
                       p->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "pwm%i", i);
                       p->name = eina_stringshare_add(buf2);
                       GETVAL_INT(buf, "enable", p->mode);
                       GETVAL_DBL(buf, "min", p->min, 255.0);
                       GETVAL_DBL(buf, "max", p->max, 255.0);
                       mon->pwms = eina_list_append(mon->pwms, p);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/freq%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x == NOVAL) break;
                  Freq *f = calloc(1, sizeof(Freq));
                  if (f)
                    {
                       f->mhz = (double)x / 1000000.0;
                       f->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "freq%i", i);
                       f->name = eina_stringshare_add(buf2);
                       GETVAL_STR(buf, "label", f->label);
                       mon->freqs = eina_list_append(mon->freqs, f);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/power%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x < 0)
                    {
                       snprintf(buf2, sizeof(buf2), "%s_%s", buf, "average");
                       x = _file_int_get(buf2);
                    }
                  if (x == NOVAL) break;
                  Power *p = calloc(1, sizeof(Power));
                  if (p)
                    {
                       p->watts = (double)x / 1000000.0;
                       p->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "power%i", i);
                       p->name = eina_stringshare_add(buf2);
                       p->enable = 1;
                       GETVAL_INT(buf, "enable", p->enable);
                       GETVAL_DBL(buf, "min", p->min, 1000000.0);
                       GETVAL_DBL(buf, "max", p->max, 1000000.0);
                       if (p->min <= 0.0)
                         GETVAL_DBL(buf, "average_min", p->min, 1000000.0);
                       if (p->max <= 0.0)
                         GETVAL_DBL(buf, "average_max", p->max, 1000000.0);
                       GETVAL_DBL(buf, "cap", p->cap, 1000000.0);
                       GETVAL_DBL(buf, "cap_min", p->cap_min, 1000000.0);
                       GETVAL_DBL(buf, "cap_max", p->cap_max, 1000000.0);
                       GETVAL_DBL(buf, "crit", p->crit, 1000000.0);
                       mon->powers = eina_list_append(mon->powers, p);
                    }
               }
             for (i = 0; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/in%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x < 0)
                    {
                       snprintf(buf2, sizeof(buf2), "%s_%s", buf, "average");
                       x = _file_int_get(buf2);
                    }
                  if (x == NOVAL) break;
                  Volt *v = calloc(1, sizeof(Volt));
                  if (v)
                    {
                       v->volts = (double)x / 1000.0;
                       v->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "in%i", i);
                       v->name = eina_stringshare_add(buf2);
                       GETVAL_STR(buf, "label", v->label);
                       v->enable = 1;
                       GETVAL_INT(buf, "enable", v->enable);
                       GETVAL_DBL(buf, "min", v->min, 1000.0);
                       GETVAL_DBL(buf, "max", v->max, 1000.0);
                       GETVAL_DBL(buf, "lcrit", v->crit_min, 1000.0);
                       GETVAL_DBL(buf, "crit", v->crit, 1000.0);
                       mon->volts = eina_list_append(mon->volts, v);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/curr%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x < 0)
                    {
                       snprintf(buf2, sizeof(buf2), "%s_%s", buf, "average");
                       x = _file_int_get(buf2);
                    }
                  if (x == NOVAL) break;
                  Amp *a = calloc(1, sizeof(Amp));
                  if (a)
                    {
                       a->amps = (double)x / 1000.0;
                       a->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "curr%i", i);
                       a->name = eina_stringshare_add(buf2);
                       a->enable = 1;
                       GETVAL_INT(buf, "enable", a->enable);
                       GETVAL_DBL(buf, "min", a->min, 1000.0);
                       GETVAL_DBL(buf, "max", a->max, 1000.0);
                       GETVAL_DBL(buf, "lcrit", a->crit_min, 1000.0);
                       GETVAL_DBL(buf, "crit", a->crit, 1000.0);
                       mon->amps = eina_list_append(mon->amps, a);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/energy%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x == NOVAL) break;
                  Energy *e = calloc(1, sizeof(Energy));
                  if (e)
                    {
                       e->joules = (double)x / 1000000.0;
                       e->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "energy%i", i);
                       e->name = eina_stringshare_add(buf2);
                       e->enable = 1;
                       GETVAL_INT(buf, "enable", e->enable);
                       mon->energies = eina_list_append(mon->energies, e);
                    }
               }
             for (i = 1; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/humidity%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "input");
                  x = _file_int_get(buf2);
                  if (x == NOVAL) break;
                  Humid *h = calloc(1, sizeof(Humid));
                  if (h)
                    {
                       h->percent = (double)x / 1000.0;
                       h->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "humidity%i", i);
                       h->name = eina_stringshare_add(buf2);
                       h->enable = 1;
                       GETVAL_INT(buf, "enable", h->enable);
                       mon->humids = eina_list_append(mon->humids, h);
                    }
               }
             for (i = 0; ; i++)
               {
                  snprintf(buf,  sizeof(buf),  "/sys/class/hwmon/%s/intrusion%i", s, i);
                  snprintf(buf2, sizeof(buf2), "%s_%s", buf, "alarm");
                  x = _file_int_get(buf2);
                  if (x == NOVAL) break;
                  Intrusion *n = calloc(1, sizeof(Intrusion));
                  if (n)
                    {
                       n->alarm = x;
                       n->path = eina_stringshare_add(buf);
                       snprintf(buf2,  sizeof(buf2),  "intrusion%i", i);
                       n->name = eina_stringshare_add(buf2);
                       mon->intrusions = eina_list_append(mon->intrusions, n);
                    }
               }
             mons = eina_list_append(mons, mon);
          }
        free(s);
     }
   eina_lock_release(&mons_lock);
}

static void
_hwmon_update(void)
{
   Eina_List *l, *ll;
   Mon *mon;
   Temp *temp;
   Fan *fan;
   Pwm *pwm;
   Freq *freq;
   Power *power;
   Volt *volt;
   Amp *amp;
   Energy *energy;
   Humid *humid;
   Intrusion *intrusion;
   int x;
   char buf[4096];

   eina_lock_take(&mons_lock);
   EINA_LIST_FOREACH(mons, l, mon)
     {
        EINA_LIST_FOREACH(mon->temps, ll, temp)
          {
             snprintf(buf, sizeof(buf), "%s_input", temp->path);
             temp->temp = (double)_file_int_get(buf) / 1000.0;
             snprintf(buf, sizeof(buf), "%s_enable", temp->path);
             x = _file_int_get(buf);
             if (x != NOVAL) temp->enable = x;
             snprintf(buf, sizeof(buf), "%s_fault", temp->path);
             temp->fault = _file_int_get(buf);
          }
        EINA_LIST_FOREACH(mon->fans, ll, fan)
          {
             snprintf(buf, sizeof(buf), "%s_input", fan->path);
             fan->rpm = _file_int_get(buf);
             snprintf(buf, sizeof(buf), "%s_target", fan->path);
             fan->target = _file_int_get(buf);
             snprintf(buf, sizeof(buf), "%s_enable", fan->path);
             x = _file_int_get(buf);
             if (x != NOVAL) fan->enable = x;
             snprintf(buf, sizeof(buf), "%s_fault", fan->path);
             fan->fault = _file_int_get(buf);
          }
        EINA_LIST_FOREACH(mon->pwms, ll, pwm)
          {
             snprintf(buf, sizeof(buf), "%s", pwm->path);
             pwm->val = (double)_file_int_get(buf) / 255.0;
             snprintf(buf, sizeof(buf), "%s_enable", pwm->path);
             x = _file_int_get(buf);
             if (x != NOVAL) pwm->mode = x;
          }
        EINA_LIST_FOREACH(mon->freqs, ll, freq)
          {
             snprintf(buf, sizeof(buf), "%s_input", freq->path);
             freq->mhz = (double)_file_int_get(buf) / 1000000.0;
          }
        EINA_LIST_FOREACH(mon->powers, ll, power)
          {
             snprintf(buf, sizeof(buf), "%s_input", power->path);
             x = _file_int_get(buf);
             if (x == NOVAL)
               {
                  snprintf(buf, sizeof(buf), "%s_average", power->path);
                  x = _file_int_get(buf);
               }
             power->watts = (double)x / 1000000.0;
             snprintf(buf, sizeof(buf), "%s_enable", power->path);
             x = _file_int_get(buf);
             if (x != NOVAL) power->enable = x;
          }
        EINA_LIST_FOREACH(mon->volts, ll, volt)
          {
             snprintf(buf, sizeof(buf), "%s_input", volt->path);
             x = _file_int_get(buf);
             if (x == NOVAL)
               {
                  snprintf(buf, sizeof(buf), "%s_average", volt->path);
                  x = _file_int_get(buf);
               }
             volt->volts = (double)x / 1000.0;
             snprintf(buf, sizeof(buf), "%s_enable", volt->path);
             x = _file_int_get(buf);
             if (x != NOVAL) volt->enable = x;
          }
        EINA_LIST_FOREACH(mon->amps, ll, amp)
          {
             snprintf(buf, sizeof(buf), "%s_input", amp->path);
             x = _file_int_get(buf);
             if (x == NOVAL)
               {
                  snprintf(buf, sizeof(buf), "%s_average", amp->path);
                  x = _file_int_get(buf);
               }
             amp->amps = (double)x / 1000.0;
             snprintf(buf, sizeof(buf), "%s_enable", amp->path);
             x = _file_int_get(buf);
             if (x != NOVAL) amp->enable = x;
          }
        EINA_LIST_FOREACH(mon->energies, ll, energy)
          {
             snprintf(buf, sizeof(buf), "%s_input", energy->path);
             energy->joules = (double)_file_int_get(buf) / 1000000.0;
             snprintf(buf, sizeof(buf), "%s_enable", energy->path);
             x = _file_int_get(buf);
             if (x != NOVAL) energy->enable = x;
         }
        EINA_LIST_FOREACH(mon->humids, ll, humid)
          {
             snprintf(buf, sizeof(buf), "%s_input", humid->path);
             humid->percent = (double)_file_int_get(buf) / 1000.0;
             snprintf(buf, sizeof(buf), "%s_enable", humid->path);
             x = _file_int_get(buf);
             if (x != NOVAL) humid->enable = x;
          }
        EINA_LIST_FOREACH(mon->intrusions, ll, intrusion)
          {
             snprintf(buf, sizeof(buf), "%s_alarm", intrusion->path);
             intrusion->alarm = _file_int_get(buf);
          }
     }
   eina_lock_release(&mons_lock);
}
#endif

typedef struct
{
#if defined (__FreeBSD__) || defined(__DragonFly__) || defined (__OpenBSD__)
   int mib[CTL_MAXNAME];
#endif
#if defined (__FreeBSD__) || defined(__DragonFly__)
   unsigned int miblen;
#endif
   int dummy;
} Extn;

#if defined (__FreeBSD__) || defined(__DragonFly__)
static const char *sources[] =
{
   "hw.acpi.thermal.tz0.temperature",
   "dev.cpu.0.temperature",
   "dev.aibs.0.temp.0",
   "dev.lm75.0.temperature",
   NULL
};
#endif

#if defined(__OpenBSD__)
static struct sensor snsr;
static size_t slen = sizeof(snsr);
#endif

static void
init(Tempthread *tth)
{
   Extn *extn;

   if (tth->initted) return;
   tth->initted = EINA_TRUE;

   extn = calloc(1, sizeof(Extn));
   if (!extn) return;

   tth->extn = extn;
   if (((!tth->sensor_name) || (tth->sensor_name[0] == 0)))
     {
        eina_stringshare_replace(&(tth->sensor_name), NULL);
#if defined (__FreeBSD__) || defined(__DragonFly__)
        unsigned int i;
        size_t len;
        int rc;

        for (i = 0; sources[i]; i++)
          {
             rc = sysctlbyname(sources[i], NULL, NULL, NULL, 0);
             if (rc == 0)
               {
                  tth->sensor_name = eina_stringshare_add(sources[i]);
                  len = sizeof(extn->mib) / sizeof(extn->mib[0]);
                  rc = sysctlnametomib(tth->sensor_name, extn->mib, &len);
                  if (rc == 0) extn->miblen = len;
                  break;
               }
          }
#elif defined(__OpenBSD__)
        int dev, numt;
        struct sensordev snsrdev;
        size_t sdlen = sizeof(snsrdev);

        extn->mib[0] = CTL_HW;
        extn->mib[1] = HW_SENSORS;
        for (dev = 0;; dev++)
          {
             extn->mib[2] = dev;
             if (sysctl(extn->mib, 3, &snsrdev, &sdlen, NULL, 0) == -1)
               {
                  if (errno == ENOENT) /* no further sensors */
                    break;
                  else
                    continue;
               }
             if (strcmp(snsrdev.xname, "cpu0") == 0)
               {
                  tth->sensor_name = eina_stringshare_add("cpu0");
                  break;
               }
             else if (strcmp(snsrdev.xname, "km0") == 0)
               {
                  tth->sensor_name = eina_stringshare_add("km0");
                  break;
               }
          }
        for (numt = 0; numt < snsrdev.maxnumt[SENSOR_TEMP]; numt++)
          {
             extn->mib[4] = numt;
             slen = sizeof(snsr);
             if (sysctl(extn->mib, 5, &snsr, &slen, NULL, 0) == -1)
               continue;
             if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0)
               break;
          }
#else
        if (!tth->sensor_name)
          {
             Eina_List *l, *ll;
             Mon *mon;
             Temp *temp;

             eina_lock_take(&mons_lock);
             EINA_LIST_FOREACH(mons, l, mon)
               {
                  EINA_LIST_FOREACH(mon->temps, ll, temp)
                    {
                       tth->sensor_name = eina_stringshare_add(temp->path);
                       break;
                    }
               }
             eina_lock_release(&mons_lock);
          }
#endif
     }
}

static int
check(Tempthread *tth)
{
#if defined (__FreeBSD__) || defined(__DragonFly__)
   Extn *extn = tth->extn;
   size_t len;
   size_t ftemp = 0;
   len = sizeof(ftemp);
   if (sysctl(extn->mib, extn->miblen, &ftemp, &len, NULL, 0) == 0)
     return (ftemp - 2732) / 10;
#elif defined (__OpenBSD__)
   Extn *extn = tth->extn;
   if (sysctl(extn->mib, 5, &snsr, &slen, NULL, 0) != -1)
     return (snsr.value - 273150000) / 1000000.0;
#else
   Eina_List *l, *ll;
   Mon *mon;
   Temp *temp;

   _hwmon_update();
   if (tth->sensor_name)
     {
        double t = 0.0;

        eina_lock_take(&mons_lock);
        EINA_LIST_FOREACH(mons, l, mon)
          {
             EINA_LIST_FOREACH(mon->temps, ll, temp)
               {
                  if (!strcmp(tth->sensor_name, temp->path))
                    {
                       t =  temp->temp;
                       break;
                    }
               }
          }
        eina_lock_release(&mons_lock);
        return t;
     }
#endif
   return -999;
}

int
temperature_tempget_get(Tempthread *tth)
{
   init(tth);
   return check(tth);
}

Eina_List *
temperature_tempget_sensor_list(void)
{
#if defined (__FreeBSD__) || defined(__DragonFly__)
   return NULL;
#elif defined (__OpenBSD__)
   return NULL;
#else
   Eina_List *sensors = NULL, *l, *ll;
   Sensor *sen;
   Mon *mon;
   Temp *temp;
   char buf[256];

   EINA_LIST_FOREACH(mons, l, mon)
     {
        EINA_LIST_FOREACH(mon->temps, ll, temp)
          {
             sen = calloc(1, sizeof(Sensor));
             sen->name = eina_stringshare_add(temp->path);
             snprintf(buf, sizeof(buf), "%s - %s",
                      mon->label ? mon->label : mon->name,
                      temp->label ? temp->label : temp->name);
             sen->label = eina_stringshare_add(buf);
             sensors = eina_list_append(sensors, sen);
          }
     }
   return sensors;
#endif
}

void
temperature_tempget_setup(void)
{
#if defined (__FreeBSD__) || defined(__DragonFly__)
#elif defined (__OpenBSD__)
#else
   eina_lock_new(&mons_lock);
   _hwmon_init();
#endif
}

void
temperature_tempget_clear(void)
{
#if defined (__FreeBSD__) || defined(__DragonFly__)
#elif defined (__OpenBSD__)
#else
   Mon *mon;
   Temp *temp;
   Fan *fan;
   Pwm *pwm;
   Freq *freq;
   Power *power;
   Volt *volt;
   Amp *amp;
   Energy *energy;
   Humid *humid;
   Intrusion *intrusion;

   eina_lock_take(&mons_lock);
   EINA_LIST_FREE(mons, mon)
     {
        eina_stringshare_replace(&(mon->path), NULL);
        eina_stringshare_replace(&(mon->name), NULL);
        eina_stringshare_replace(&(mon->label), NULL);
        EINA_LIST_FREE(mon->temps, temp)
          {
             eina_stringshare_replace(&(temp->path), NULL);
             eina_stringshare_replace(&(temp->name), NULL);
             eina_stringshare_replace(&(temp->label), NULL);
             free(temp);
          }
        EINA_LIST_FREE(mon->fans, fan)
          {
             eina_stringshare_replace(&(fan->path), NULL);
             eina_stringshare_replace(&(fan->name), NULL);
             eina_stringshare_replace(&(fan->label), NULL);
             free(fan);
          }
        EINA_LIST_FREE(mon->pwms, pwm)
          {
             eina_stringshare_replace(&(pwm->path), NULL);
             eina_stringshare_replace(&(pwm->name), NULL);
             free(fan);
          }
        EINA_LIST_FREE(mon->freqs, freq)
          {
             eina_stringshare_replace(&(freq->path), NULL);
             eina_stringshare_replace(&(freq->name), NULL);
             eina_stringshare_replace(&(freq->label), NULL);
             free(freq);
          }
        EINA_LIST_FREE(mon->powers, power)
          {
             eina_stringshare_replace(&(power->path), NULL);
             eina_stringshare_replace(&(power->name), NULL);
             free(power);
          }
        EINA_LIST_FREE(mon->volts, volt)
          {
             eina_stringshare_replace(&(volt->path), NULL);
             eina_stringshare_replace(&(volt->name), NULL);
             eina_stringshare_replace(&(volt->label), NULL);
             free(volt);
          }
        EINA_LIST_FREE(mon->amps, amp)
          {
             eina_stringshare_replace(&(amp->path), NULL);
             eina_stringshare_replace(&(amp->name), NULL);
             free(amp);
          }
        EINA_LIST_FREE(mon->energies, energy)
          {
             eina_stringshare_replace(&(energy->path), NULL);
             eina_stringshare_replace(&(energy->name), NULL);
             free(energy);
          }
        EINA_LIST_FREE(mon->humids, humid)
          {
             eina_stringshare_replace(&(humid->path), NULL);
             eina_stringshare_replace(&(humid->name), NULL);
             free(humid);
          }
        EINA_LIST_FREE(mon->intrusions, intrusion)
          {
             eina_stringshare_replace(&(intrusion->path), NULL);
             eina_stringshare_replace(&(intrusion->name), NULL);
             free(intrusion);
          }
        free(mon);
     }
   eina_lock_release(&mons_lock);
   // extra lock take to cover race cond for thread
   eina_lock_take(&mons_lock);
   eina_lock_release(&mons_lock);
   eina_lock_free(&mons_lock);
#endif
}
