aboutsummaryrefslogtreecommitdiff
path: root/toys/other/acpi.c
blob: 3e19141cca58c976f54495bd20abc5440675bec0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* acpi.c - show power state
 *
 * Written by Isaac Dunham, 2013
 *
 * No standard.

USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))

config ACPI
  bool "acpi"
  default y
  help
    usage: acpi [-abctV]
    
    Show status of power sources and thermal devices.

    -a	Show power adapters
    -b	Show batteries
    -c	Show cooling device state
    -t	Show temperatures
    -V	Show everything
*/

#define FOR_acpi
#include "toys.h"

GLOBALS(
  int ac, bat, therm, cool;
  char *cpath;
)

static int read_int_at(int dirfd, char *name)
{
  int fd, ret=0;
  FILE *fil;

  if ((fd = openat(dirfd, name, O_RDONLY)) < 0) return -1;
  if (!fscanf(fil = xfdopen(fd, "r"), "%d", &ret)) perror_exit_raw(name);
  fclose(fil);

  return ret;
}

static int acpi_callback(struct dirtree *tree)
{
  int dfd, fd, len, on;

  errno = 0;

  if (tree->name[0]=='.') return 0;

  if (!tree->parent)
    return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;

  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
    if ((fd = openat(dfd, "type", O_RDONLY)) < 0) goto done;
    len = readall(fd, toybuf, sizeof(toybuf));
    close(fd);
    if (len < 1) goto done;

    if (!strncmp(toybuf, "Battery", 7)) {
      if ((toys.optflags & FLAG_b) || (!toys.optflags)) {
        int cap = 0, curr = 0, max = 0;

        if ((cap = read_int_at(dfd, "capacity")) < 0) {
          if ((max = read_int_at(dfd, "charge_full")) > 0)
            curr = read_int_at(dfd, "charge_now");
          else if ((max = read_int_at(dfd, "energy_full")) > 0)
            curr = read_int_at(dfd, "energy_now");
          if (max > 0 && curr >= 0) cap = 100 * curr / max;
        }
        if (cap >= 0) printf("Battery %d: %d%%\n", TT.bat++, cap);
      }
    } else if (toys.optflags & FLAG_a) {
      if ((on = read_int_at(dfd, "online")) >= 0)
        printf("Adapter %d: %s-line\n", TT.ac++, (on ? "on" : "off"));
    }
done:
    close(dfd);
  }
  free(TT.cpath);
  return 0;
}

static int temp_callback(struct dirtree *tree)
{
  int dfd, temp;

  if (*tree->name=='.') return 0;
  if (!tree->parent || !tree->parent->parent)
    return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
  errno = 0;

  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
    if ((0 < (temp = read_int_at(dfd, "temp"))) || !errno) {
      //some tempertures are in milli-C, some in deci-C
      //reputedly some are in deci-K, but I have not seen them
      if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0)) temp /= 100;
      printf("Thermal %d: %d.%d degrees C\n", TT.therm++, temp/10, temp%10);
    }
    close(dfd);
  }
  free(TT.cpath);

  return 0;
}

static int cool_callback(struct dirtree *tree)
{
  int dfd=5, cur, max;

  errno = 0;
  memset(toybuf, 0, sizeof(toybuf));

  if (*tree->name == '.') return 0;
  if (!tree->parent) return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;


  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, &dfd)), O_RDONLY))) {
    TT.cpath = strcat(TT.cpath, "/type");
    if (readfile(TT.cpath, toybuf, 256) && !errno) {
      toybuf[strlen(toybuf) -1] = 0;
      cur=read_int_at(dfd, "cur_state");
      max=read_int_at(dfd, "max_state");
      if (errno)
        printf("Cooling %d: %s no state information\n", TT.cool++, toybuf);
      else printf("Cooling %d: %s %d of %d\n", TT.cool++, toybuf, cur, max);
    }
    close(dfd);
  }
  free(TT.cpath);
  return 0;
}

void acpi_main(void)
{
  if (toys.optflags & FLAG_V) toys.optflags = FLAG_a|FLAG_b|FLAG_c|FLAG_t;
  if (!toys.optflags) toys.optflags = FLAG_b;
  if (toys.optflags & (FLAG_a|FLAG_b))
    dirtree_read("/sys/class/power_supply", acpi_callback);
  if (toys.optflags & FLAG_t) dirtree_read("/sys/class", temp_callback);
  if (toys.optflags & FLAG_c) dirtree_read("/sys/class/thermal", cool_callback);
}