Codebase list i3status / d0e264d
Imported Upstream version 2.9 Michael Stapelberg 9 years ago
29 changed file(s) with 3678 addition(s) and 2668 deletion(s). Raw diff Collapse all Expand all
0 2015-03-22 i3status 2.9
1
2 • meta: i3status is now on GitHub and uses clang-format
3 • allow customization of the module separator
4 • add “align” and “min_width” options for each module
5 • fix CFLAGS and LDFLAGS for DragonFly and FreeBSD
6 • add contrib/net-speed, a more light-weight reimplementation of
7 contrib/measure-net-speed.bash
8 • battery: add hide_seconds option
9 • battery: fix for systems without POWER_SUPPLY_VOLTAGE_NOW
10 • battery: for %percentage, drop leading 0 for values < 10
11 • battery: add NetBSD support
12 • battery: use absolute values for (dis)charging rates
13 • battery: introduce status_{chr,bat,full}
14 • cpu_temperature: fix displaying multiple sensors
15 • cpu_temperature: fix NetBSD support
16 • cpu_temperature: fix DragonFly support
17 • disk: introduce threshold_type and low_threshold
18 • disk: add format_not_mounted for unmounted paths
19 • ethernet, wireless: support special interface name _first_
20 • run_watch: check all matching pid files until first valid one
21 • volume: fix wrong color tags with xmobar
22 • wireless: support %frequency (2.4 vs. 5 GHz)
23
024 2014-01-05 i3status 2.8
125
226 • Fix build on GNU/Hurd
1818 LIBS+=-lconfuse
1919 LIBS+=-lyajl
2020
21 VERSION=2.8
22 GIT_VERSION="2.8 (2014-01-05)"
21 VERSION=2.9
22 GIT_VERSION="2.9 (2015-03-22)"
2323 OS:=$(shell uname)
2424
2525 ifeq ($(OS),Linux)
3333 LIBS+=-lbsd
3434 endif
3535
36 ifeq ($(OS),OpenBSD)
36 ifneq (, $(filter $(OS), DragonFly FreeBSD OpenBSD))
3737 CFLAGS+=-I/usr/local/include/
3838 LDFLAGS+=-L/usr/local/lib/
39 endif
40
41 ifeq ($(OS),OpenBSD)
3942 LIBS+=-lossaudio
4043 endif
4144
45 ifeq ($(OS), NetBSD)
46 LIBS+= -lprop
47 endif
4248
4349 # This probably applies for any pkgsrc based system
4450 ifneq (, $(filter $(OS), NetBSD DragonFly))
4551 CFLAGS+=-I/usr/pkg/include/
4652 LDFLAGS+=-L/usr/pkg/lib/
4753 endif
48
49 ifeq ($(OS), NetBSD)
50 LIBS+= -lprop
51 endif
52
5354
5455 V ?= 0
5556 ifeq ($(V),0)
102103 release:
103104 [ -f i3status-${VERSION} ] || rm -rf i3status-${VERSION}
104105 mkdir i3status-${VERSION}
105 find . -maxdepth 1 -type f \( -regex ".*\.\(c\|conf\|h\)" -or -name "Makefile" -or -name "LICENSE" -or -name "CHANGELOG" \) -exec cp '{}' i3status-${VERSION} \;
106 find . -maxdepth 1 -type f \( -regex ".*\.\(c\|conf\|h\)" -or -name "README" -or -name "Makefile" -or -name "LICENSE" -or -name "CHANGELOG" \) -exec cp '{}' i3status-${VERSION} \;
106107 mkdir i3status-${VERSION}/src
107108 mkdir i3status-${VERSION}/man
108109 find src -maxdepth 1 -type f \( -regex ".*\.\(c\|h\)" \) -exec cp '{}' i3status-${VERSION}/src \;
0 ┌────────────────────────────┐
1 │ Description │
2 └────────────────────────────┘
3
4 i3status is a small program (about 1500 SLOC) for generating a status bar for
5 i3bar, dzen2, xmobar or similar programs. It is designed to be very efficient by
6 issuing a very small number of system calls, as one generally wants to update
7 such a status line every second. This ensures that even under high load, your
8 status bar is updated correctly. Also, it saves a bit of energy by not hogging
9 your CPU as much as spawning the corresponding amount of shell commands would.
10
11 ┌────────────────────────────┐
12 │ Development │
13 └────────────────────────────┘
14
15 i3status has the following dependencies:
16 • libconfuse-dev
17 • libyajl-dev
18 • libasound2-dev
19 • libiw-dev
20 • libcap2-bin (for getting network status without root permissions)
21 • asciidoc (only for the documentation)
22
23 On debian-based systems, the following line will install all requirements:
24 apt-get install libconfuse-dev libyajl-dev libasound2-dev libiw-dev asciidoc libcap2-bin
25
26 ┌────────────────────────────┐
27 │ Upstream │
28 └────────────────────────────┘
29
30 i3status is developed at
31 https://github.com/i3/i3status
32
33 ┌────────────────────────────┐
34 │ Compilation │
35 └────────────────────────────┘
36
37 Compiling is done with the usual make-line
38 make && sudo make install
0 #!/bin/sh
1 # Copyright (c) 2014 Zhong Jianxin <azuwis@gmail.com>
2
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 # THE SOFTWARE.
20
21 # Thank Stefan Breunig for the original implementation, see
22 # contrib/measure-net-speed.bash.
23
24 # i3status.conf should contain:
25 # general {
26 # output_format = i3bar
27 # }
28
29 # i3 config looks like this:
30 # bar {
31 # status_command exec /usr/share/doc/i3status/contrib/net-speed
32 # }
33
34 # Single interface
35 #ifaces="eth0"
36
37 # Multiple interfaces
38 #ifaces="eth0 wlan0"
39
40 # Auto detect
41 ifaces=$(ls /sys/class/net | grep -E '^(eth|wlan)')
42
43 # Interval must be the same as in i3status.conf
44 #interval=5
45
46 # Auto detect
47 if [ -f ~/.i3status.conf ]; then
48 i3status_conf=~/.i3status.conf
49 else
50 i3status_conf="/etc/i3status.conf"
51 fi
52 interval=$(grep -o '^[[:space:]]*interval[[:space:]]*=[[:space:]]*[[:digit:]]\+' $i3status_conf | grep -o '[[:digit:]]\+')
53 if [ x"$interval" = x ]; then
54 interval=5
55 fi
56
57 last_rx=0
58 last_tx=0
59 rate=""
60
61 readable() {
62 local byte=$1
63 local kib=$(( byte >> 10 ))
64 if [ "$kib" -gt 1024 ]; then
65 local mib_int=$(( kib >> 10 ))
66 local mib_dec=$(( kib % 1024 * 976 / 10000 ))
67 if [ "$mib_dec" -lt 10 ]; then
68 mib_dec="0${mib_dec}"
69 fi
70 echo "${mib_int}.${mib_dec}M"
71 else
72 echo "${kib}K"
73 fi
74 }
75
76 update_rate() {
77 local rx=0
78 local tx=0
79 for iface in $ifaces; do
80 local tmp_rx
81 local tmp_tx
82 local stat="/sys/class/net/${iface}/statistics"
83 read tmp_rx < "${stat}/rx_bytes"
84 read tmp_tx < "${stat}/tx_bytes"
85 rx=$(( rx + tmp_rx ))
86 tx=$(( tx + tmp_tx ))
87 done
88 rate="$(readable $(( (rx - last_rx) / interval )))↓ $(readable $(( (tx - last_tx) / interval )))↑"
89 last_rx=$rx
90 last_tx=$tx
91 }
92
93 # while :; do
94 # update_rate
95 # echo "$rate"
96 # sleep "$interval"
97 # done
98
99 i3status | (read line && echo "$line" && read line && echo "$line" && read line && echo "$line" && update_rate && while :
100 do
101 read line
102 update_rate
103 echo ",[{\"full_text\":\"${rate}\" },${line#,\[}" || exit 1
104 done)
00 /*
1 * vim:ts=8:expandtab
1 * vim:ts=4:sw=4:expandtab
22 *
33 * i3status – Generates a status line for dzen2 or xmobar
44 *
1010 * See file LICENSE for license information.
1111 *
1212 */
13 #include <limits.h>
1314 #include <string.h>
1415 #include <stdio.h>
1516 #include <stdbool.h>
3233
3334 #include "i3status.h"
3435
35 #define exit_if_null(pointer, ...) { if (pointer == NULL) die(__VA_ARGS__); }
36
37 #define CFG_COLOR_OPTS(good, degraded, bad) \
38 CFG_STR("color_good", good, CFGF_NONE), \
39 CFG_STR("color_degraded", degraded, CFGF_NONE), \
40 CFG_STR("color_bad", bad, CFGF_NONE)
36 #define exit_if_null(pointer, ...) \
37 { \
38 if (pointer == NULL) \
39 die(__VA_ARGS__); \
40 }
41
42 #define CFG_CUSTOM_ALIGN_OPT \
43 CFG_STR_CB("align", NULL, CFGF_NONE, parse_align)
44
45 #define CFG_COLOR_OPTS(good, degraded, bad) \
46 CFG_STR("color_good", good, CFGF_NONE), \
47 CFG_STR("color_degraded", degraded, CFGF_NONE), \
48 CFG_STR("color_bad", bad, CFGF_NONE)
4149
4250 #define CFG_CUSTOM_COLOR_OPTS CFG_COLOR_OPTS(NULL, NULL, NULL)
51
52 #define CFG_CUSTOM_MIN_WIDTH_OPT \
53 CFG_PTR_CB("min_width", NULL, CFGF_NONE, parse_min_width, free)
4354
4455 /* socket file descriptor for general purposes */
4556 int general_socket;
4758 static bool exit_upon_signal = false;
4859
4960 cfg_t *cfg, *cfg_general, *cfg_section;
61
62 void **cur_instance;
5063
5164 /*
5265 * Set the exit_upon_signal flag, because one cannot do anything in a safe
5669 *
5770 */
5871 void fatalsig(int signum) {
59 exit_upon_signal = true;
72 exit_upon_signal = true;
6073 }
6174
6275 /*
7285 *
7386 */
7487 static bool path_exists(const char *path) {
75 struct stat buf;
76 return (stat(path, &buf) == 0);
88 struct stat buf;
89 return (stat(path, &buf) == 0);
7790 }
7891
7992 static void *scalloc(size_t size) {
80 void *result = calloc(size, 1);
81 exit_if_null(result, "Error: out of memory (calloc(%zd))\n", size);
82 return result;
93 void *result = calloc(size, 1);
94 exit_if_null(result, "Error: out of memory (calloc(%zd))\n", size);
95 return result;
8396 }
8497
8598 static char *sstrdup(const char *str) {
86 char *result = strdup(str);
87 exit_if_null(result, "Error: out of memory (strdup())\n");
88 return result;
89 }
90
99 char *result = strdup(str);
100 exit_if_null(result, "Error: out of memory (strdup())\n");
101 return result;
102 }
103
104 /*
105 * Parses the "align" module option (to validate input).
106 */
107 static int parse_align(cfg_t *context, cfg_opt_t *option, const char *value, void *result) {
108 if (strcasecmp(value, "left") != 0 && strcasecmp(value, "right") != 0 && strcasecmp(value, "center") != 0)
109 die("Invalid alignment attribute found in section %s, line %d: \"%s\"\n"
110 "Valid attributes are: left, center, right\n",
111 context->name, context->line, value);
112
113 const char **cresult = result;
114 *cresult = value;
115
116 return 0;
117 }
118
119 /*
120 * Parses the "min_width" module option whose value can either be a string or an integer.
121 */
122 static int parse_min_width(cfg_t *context, cfg_opt_t *option, const char *value, void *result) {
123 char *end;
124 long num = strtol(value, &end, 10);
125
126 if (num < 0)
127 die("Invalid min_width attribute found in section %s, line %d: %d\n"
128 "Expected positive integer or string\n",
129 context->name, context->line, num);
130 else if (num == LONG_MIN || num == LONG_MAX || (end && *end != '\0'))
131 num = 0;
132
133 if (strlen(value) == 0)
134 die("Empty min_width attribute found in section %s, line %d\n"
135 "Expected positive integer or non-empty string\n",
136 context->name, context->line);
137
138 if (strcmp(value, "0") == 0)
139 die("Invalid min_width attribute found in section %s, line %d: \"%s\"\n"
140 "Expected positive integer or string\n",
141 context->name, context->line, value);
142
143 struct min_width *parsed = scalloc(sizeof(struct min_width));
144 parsed->num = num;
145
146 /* num is preferred, but if it’s 0 (i.e. not valid), store and use
147 * the raw string value */
148 if (num == 0)
149 parsed->str = sstrdup(value);
150
151 struct min_width **cresult = result;
152 *cresult = parsed;
153
154 return 0;
155 }
91156
92157 /*
93158 * Validates a color in "#RRGGBB" format
94159 *
95160 */
96 static int valid_color(const char *value)
97 {
98 if (strlen(value) != 7) return 0;
99 if (value[0] != '#') return 0;
100 for (int i = 1; i < 7; ++i) {
101 if (value[i] >= '0' && value[i] <= '9') continue;
102 if (value[i] >= 'a' && value[i] <= 'f') continue;
103 if (value[i] >= 'A' && value[i] <= 'F') continue;
104 return 0;
105 }
106 return 1;
161 static int valid_color(const char *value) {
162 if (strlen(value) != 7)
163 return 0;
164 if (value[0] != '#')
165 return 0;
166 for (int i = 1; i < 7; ++i) {
167 if (value[i] >= '0' && value[i] <= '9')
168 continue;
169 if (value[i] >= 'a' && value[i] <= 'f')
170 continue;
171 if (value[i] >= 'A' && value[i] <= 'F')
172 continue;
173 return 0;
174 }
175 return 1;
107176 }
108177
109178 /*
113182 *
114183 */
115184 static char *resolve_tilde(const char *path) {
116 static glob_t globbuf;
117 char *head, *tail, *result = NULL;
118
119 tail = strchr(path, '/');
120 head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
121
122 int res = glob(head, GLOB_TILDE, NULL, &globbuf);
123 free(head);
124 /* no match, or many wildcard matches are bad */
125 if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
126 result = sstrdup(path);
127 else if (res != 0) {
128 die("glob() failed");
185 static glob_t globbuf;
186 char *head, *tail, *result = NULL;
187
188 tail = strchr(path, '/');
189 head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
190
191 int res = glob(head, GLOB_TILDE, NULL, &globbuf);
192 free(head);
193 /* no match, or many wildcard matches are bad */
194 if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
195 result = sstrdup(path);
196 else if (res != 0) {
197 die("glob() failed");
198 } else {
199 head = globbuf.gl_pathv[0];
200 result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1);
201 strncpy(result, head, strlen(head));
202 if (tail)
203 strncat(result, tail, strlen(tail));
204 }
205 globfree(&globbuf);
206
207 return result;
208 }
209
210 static char *get_config_path(void) {
211 char *xdg_config_home, *xdg_config_dirs, *config_path;
212
213 /* 1: check the traditional path under the home directory */
214 config_path = resolve_tilde("~/.i3status.conf");
215 if (path_exists(config_path))
216 return config_path;
217
218 /* 2: check for $XDG_CONFIG_HOME/i3status/config */
219 if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
220 xdg_config_home = "~/.config";
221
222 xdg_config_home = resolve_tilde(xdg_config_home);
223 if (asprintf(&config_path, "%s/i3status/config", xdg_config_home) == -1)
224 die("asprintf() failed");
225 free(xdg_config_home);
226
227 if (path_exists(config_path))
228 return config_path;
229 free(config_path);
230
231 /* 3: check the traditional path under /etc */
232 config_path = SYSCONFDIR "/i3status.conf";
233 if (path_exists(config_path))
234 return sstrdup(config_path);
235
236 /* 4: check for $XDG_CONFIG_DIRS/i3status/config */
237 if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
238 xdg_config_dirs = "/etc/xdg";
239
240 char *buf = strdup(xdg_config_dirs);
241 char *tok = strtok(buf, ":");
242 while (tok != NULL) {
243 tok = resolve_tilde(tok);
244 if (asprintf(&config_path, "%s/i3status/config", tok) == -1)
245 die("asprintf() failed");
246 free(tok);
247 if (path_exists(config_path)) {
248 free(buf);
249 return config_path;
250 }
251 free(config_path);
252 tok = strtok(NULL, ":");
253 }
254 free(buf);
255
256 die("Unable to find the configuration file (looked at "
257 "~/.i3status.conf, $XDG_CONFIG_HOME/i3status/config, "
258 "/etc/i3status.conf and $XDG_CONFIG_DIRS/i3status/config)");
259 return NULL;
260 }
261
262 /*
263 * Returns the default separator to use if no custom separator has been specified.
264 */
265 static char *get_default_separator() {
266 if (output_format == O_DZEN2)
267 return "^p(5;-2)^ro(2)^p()^p(5)";
268 if (output_format == O_I3BAR)
269 // anything besides the empty string indicates that the default separator should be used
270 return "default";
271 return " | ";
272 }
273
274 int main(int argc, char *argv[]) {
275 unsigned int j;
276
277 cfg_opt_t general_opts[] = {
278 CFG_STR("output_format", "auto", CFGF_NONE),
279 CFG_BOOL("colors", 1, CFGF_NONE),
280 CFG_STR("separator", "default", CFGF_NONE),
281 CFG_STR("color_separator", "#333333", CFGF_NONE),
282 CFG_INT("interval", 1, CFGF_NONE),
283 CFG_COLOR_OPTS("#00FF00", "#FFFF00", "#FF0000"),
284 CFG_END()};
285
286 cfg_opt_t run_watch_opts[] = {
287 CFG_STR("pidfile", NULL, CFGF_NONE),
288 CFG_STR("format", "%title: %status", CFGF_NONE),
289 CFG_CUSTOM_ALIGN_OPT,
290 CFG_CUSTOM_COLOR_OPTS,
291 CFG_CUSTOM_MIN_WIDTH_OPT,
292 CFG_END()};
293
294 cfg_opt_t path_exists_opts[] = {
295 CFG_STR("path", NULL, CFGF_NONE),
296 CFG_STR("format", "%title: %status", CFGF_NONE),
297 CFG_CUSTOM_ALIGN_OPT,
298 CFG_CUSTOM_COLOR_OPTS,
299 CFG_CUSTOM_MIN_WIDTH_OPT,
300 CFG_END()};
301
302 cfg_opt_t wireless_opts[] = {
303 CFG_STR("format_up", "W: (%quality at %essid, %bitrate) %ip", CFGF_NONE),
304 CFG_STR("format_down", "W: down", CFGF_NONE),
305 CFG_CUSTOM_ALIGN_OPT,
306 CFG_CUSTOM_COLOR_OPTS,
307 CFG_CUSTOM_MIN_WIDTH_OPT,
308 CFG_END()};
309
310 cfg_opt_t ethernet_opts[] = {
311 CFG_STR("format_up", "E: %ip (%speed)", CFGF_NONE),
312 CFG_STR("format_down", "E: down", CFGF_NONE),
313 CFG_CUSTOM_ALIGN_OPT,
314 CFG_CUSTOM_COLOR_OPTS,
315 CFG_CUSTOM_MIN_WIDTH_OPT,
316 CFG_END()};
317
318 cfg_opt_t ipv6_opts[] = {
319 CFG_STR("format_up", "%ip", CFGF_NONE),
320 CFG_STR("format_down", "no IPv6", CFGF_NONE),
321 CFG_CUSTOM_ALIGN_OPT,
322 CFG_CUSTOM_COLOR_OPTS,
323 CFG_CUSTOM_MIN_WIDTH_OPT,
324 CFG_END()};
325
326 cfg_opt_t battery_opts[] = {
327 CFG_STR("format", "%status %percentage %remaining", CFGF_NONE),
328 CFG_STR("format_down", "No battery", CFGF_NONE),
329 CFG_STR("status_chr", "CHR", CFGF_NONE),
330 CFG_STR("status_bat", "BAT", CFGF_NONE),
331 CFG_STR("status_full", "FULL", CFGF_NONE),
332 CFG_STR("path", "/sys/class/power_supply/BAT%d/uevent", CFGF_NONE),
333 CFG_INT("low_threshold", 30, CFGF_NONE),
334 CFG_STR("threshold_type", "time", CFGF_NONE),
335 CFG_BOOL("last_full_capacity", false, CFGF_NONE),
336 CFG_BOOL("integer_battery_capacity", false, CFGF_NONE),
337 CFG_BOOL("hide_seconds", false, CFGF_NONE),
338 CFG_CUSTOM_ALIGN_OPT,
339 CFG_CUSTOM_COLOR_OPTS,
340 CFG_CUSTOM_MIN_WIDTH_OPT,
341 CFG_END()};
342
343 cfg_opt_t time_opts[] = {
344 CFG_STR("format", "%Y-%m-%d %H:%M:%S", CFGF_NONE),
345 CFG_CUSTOM_ALIGN_OPT,
346 CFG_CUSTOM_MIN_WIDTH_OPT,
347 CFG_END()};
348
349 cfg_opt_t tztime_opts[] = {
350 CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
351 CFG_STR("timezone", "", CFGF_NONE),
352 CFG_CUSTOM_ALIGN_OPT,
353 CFG_CUSTOM_MIN_WIDTH_OPT,
354 CFG_END()};
355
356 cfg_opt_t ddate_opts[] = {
357 CFG_STR("format", "%{%a, %b %d%}, %Y%N - %H", CFGF_NONE),
358 CFG_CUSTOM_ALIGN_OPT,
359 CFG_CUSTOM_MIN_WIDTH_OPT,
360 CFG_END()};
361
362 cfg_opt_t load_opts[] = {
363 CFG_STR("format", "%1min %5min %15min", CFGF_NONE),
364 CFG_FLOAT("max_threshold", 5, CFGF_NONE),
365 CFG_CUSTOM_ALIGN_OPT,
366 CFG_CUSTOM_COLOR_OPTS,
367 CFG_CUSTOM_MIN_WIDTH_OPT,
368 CFG_END()};
369
370 cfg_opt_t usage_opts[] = {
371 CFG_STR("format", "%usage", CFGF_NONE),
372 CFG_CUSTOM_ALIGN_OPT,
373 CFG_CUSTOM_MIN_WIDTH_OPT,
374 CFG_END()};
375
376 cfg_opt_t temp_opts[] = {
377 CFG_STR("format", "%degrees C", CFGF_NONE),
378 CFG_STR("path", NULL, CFGF_NONE),
379 CFG_INT("max_threshold", 75, CFGF_NONE),
380 CFG_CUSTOM_ALIGN_OPT,
381 CFG_CUSTOM_COLOR_OPTS,
382 CFG_CUSTOM_MIN_WIDTH_OPT,
383 CFG_END()};
384
385 cfg_opt_t disk_opts[] = {
386 CFG_STR("format", "%free", CFGF_NONE),
387 CFG_STR("format_not_mounted", NULL, CFGF_NONE),
388 CFG_STR("prefix_type", "binary", CFGF_NONE),
389 CFG_STR("threshold_type", "percentage_avail", CFGF_NONE),
390 CFG_FLOAT("low_threshold", 0, CFGF_NONE),
391 CFG_CUSTOM_ALIGN_OPT,
392 CFG_CUSTOM_COLOR_OPTS,
393 CFG_CUSTOM_MIN_WIDTH_OPT,
394 CFG_END()};
395
396 cfg_opt_t volume_opts[] = {
397 CFG_STR("format", "♪: %volume", CFGF_NONE),
398 CFG_STR("format_muted", "♪: 0%%", CFGF_NONE),
399 CFG_STR("device", "default", CFGF_NONE),
400 CFG_STR("mixer", "Master", CFGF_NONE),
401 CFG_INT("mixer_idx", 0, CFGF_NONE),
402 CFG_CUSTOM_ALIGN_OPT,
403 CFG_CUSTOM_COLOR_OPTS,
404 CFG_CUSTOM_MIN_WIDTH_OPT,
405 CFG_END()};
406
407 cfg_opt_t opts[] = {
408 CFG_STR_LIST("order", "{}", CFGF_NONE),
409 CFG_SEC("general", general_opts, CFGF_NONE),
410 CFG_SEC("run_watch", run_watch_opts, CFGF_TITLE | CFGF_MULTI),
411 CFG_SEC("path_exists", path_exists_opts, CFGF_TITLE | CFGF_MULTI),
412 CFG_SEC("wireless", wireless_opts, CFGF_TITLE | CFGF_MULTI),
413 CFG_SEC("ethernet", ethernet_opts, CFGF_TITLE | CFGF_MULTI),
414 CFG_SEC("battery", battery_opts, CFGF_TITLE | CFGF_MULTI),
415 CFG_SEC("cpu_temperature", temp_opts, CFGF_TITLE | CFGF_MULTI),
416 CFG_SEC("disk", disk_opts, CFGF_TITLE | CFGF_MULTI),
417 CFG_SEC("volume", volume_opts, CFGF_TITLE | CFGF_MULTI),
418 CFG_SEC("ipv6", ipv6_opts, CFGF_NONE),
419 CFG_SEC("time", time_opts, CFGF_NONE),
420 CFG_SEC("tztime", tztime_opts, CFGF_TITLE | CFGF_MULTI),
421 CFG_SEC("ddate", ddate_opts, CFGF_NONE),
422 CFG_SEC("load", load_opts, CFGF_NONE),
423 CFG_SEC("cpu_usage", usage_opts, CFGF_NONE),
424 CFG_END()};
425
426 char *configfile = NULL;
427 int o, option_index = 0;
428 struct option long_options[] = {
429 {"config", required_argument, 0, 'c'},
430 {"help", no_argument, 0, 'h'},
431 {"version", no_argument, 0, 'v'},
432 {0, 0, 0, 0}};
433
434 struct sigaction action;
435 memset(&action, 0, sizeof(struct sigaction));
436 action.sa_handler = fatalsig;
437
438 /* Exit upon SIGPIPE because when we have nowhere to write to, gathering system
439 * information is pointless. Also exit explicitly on SIGTERM and SIGINT because
440 * only this will trigger a reset of the cursor in the terminal output-format.
441 */
442 sigaction(SIGPIPE, &action, NULL);
443 sigaction(SIGTERM, &action, NULL);
444 sigaction(SIGINT, &action, NULL);
445
446 memset(&action, 0, sizeof(struct sigaction));
447 action.sa_handler = sigusr1;
448 sigaction(SIGUSR1, &action, NULL);
449
450 if (setlocale(LC_ALL, "") == NULL)
451 die("Could not set locale. Please make sure all your LC_* / LANG settings are correct.");
452
453 while ((o = getopt_long(argc, argv, "c:hv", long_options, &option_index)) != -1)
454 if ((char)o == 'c')
455 configfile = optarg;
456 else if ((char)o == 'h') {
457 printf("i3status " VERSION " © 2008-2012 Michael Stapelberg and contributors\n"
458 "Syntax: %s [-c <configfile>] [-h] [-v]\n",
459 argv[0]);
460 return 0;
461 } else if ((char)o == 'v') {
462 printf("i3status " VERSION " © 2008-2012 Michael Stapelberg and contributors\n");
463 return 0;
464 }
465
466 if (configfile == NULL)
467 configfile = get_config_path();
468
469 cfg = cfg_init(opts, CFGF_NOCASE);
470 if (cfg_parse(cfg, configfile) == CFG_PARSE_ERROR)
471 return EXIT_FAILURE;
472
473 if (cfg_size(cfg, "order") == 0)
474 die("Your 'order' array is empty. Please fix your config.\n");
475
476 cfg_general = cfg_getsec(cfg, "general");
477 if (cfg_general == NULL)
478 die("Could not get section \"general\"\n");
479
480 char *output_str = cfg_getstr(cfg_general, "output_format");
481 if (strcasecmp(output_str, "auto") == 0) {
482 fprintf(stderr, "i3status: trying to auto-detect output_format setting\n");
483 output_str = auto_detect_format();
484 if (!output_str) {
485 output_str = "none";
486 fprintf(stderr, "i3status: falling back to \"none\"\n");
129487 } else {
130 head = globbuf.gl_pathv[0];
131 result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1);
132 strncpy(result, head, strlen(head));
133 if (tail)
134 strncat(result, tail, strlen(tail));
488 fprintf(stderr, "i3status: auto-detected \"%s\"\n", output_str);
135489 }
136 globfree(&globbuf);
137
138 return result;
139 }
140
141 static char *get_config_path(void) {
142 char *xdg_config_home, *xdg_config_dirs, *config_path;
143
144 /* 1: check the traditional path under the home directory */
145 config_path = resolve_tilde("~/.i3status.conf");
146 if (path_exists(config_path))
147 return config_path;
148
149 /* 2: check for $XDG_CONFIG_HOME/i3status/config */
150 if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
151 xdg_config_home = "~/.config";
152
153 xdg_config_home = resolve_tilde(xdg_config_home);
154 if (asprintf(&config_path, "%s/i3status/config", xdg_config_home) == -1)
155 die("asprintf() failed");
156 free(xdg_config_home);
157
158 if (path_exists(config_path))
159 return config_path;
160 free(config_path);
161
162 /* 3: check the traditional path under /etc */
163 config_path = SYSCONFDIR "/i3status.conf";
164 if (path_exists(config_path))
165 return sstrdup(config_path);
166
167 /* 4: check for $XDG_CONFIG_DIRS/i3status/config */
168 if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
169 xdg_config_dirs = "/etc/xdg";
170
171 char *buf = strdup(xdg_config_dirs);
172 char *tok = strtok(buf, ":");
173 while (tok != NULL) {
174 tok = resolve_tilde(tok);
175 if (asprintf(&config_path, "%s/i3status/config", tok) == -1)
176 die("asprintf() failed");
177 free(tok);
178 if (path_exists(config_path)) {
179 free(buf);
180 return config_path;
181 }
182 free(config_path);
183 tok = strtok(NULL, ":");
490 }
491
492 if (strcasecmp(output_str, "dzen2") == 0)
493 output_format = O_DZEN2;
494 else if (strcasecmp(output_str, "xmobar") == 0)
495 output_format = O_XMOBAR;
496 else if (strcasecmp(output_str, "i3bar") == 0)
497 output_format = O_I3BAR;
498 else if (strcasecmp(output_str, "term") == 0)
499 output_format = O_TERM;
500 else if (strcasecmp(output_str, "none") == 0)
501 output_format = O_NONE;
502 else
503 die("Unknown output format: \"%s\"\n", output_str);
504
505 const char *separator = cfg_getstr(cfg_general, "separator");
506
507 // if no custom separator has been provided, use the default one
508 if (strcasecmp(separator, "default") == 0)
509 separator = get_default_separator();
510
511 if (!valid_color(cfg_getstr(cfg_general, "color_good")) || !valid_color(cfg_getstr(cfg_general, "color_degraded")) || !valid_color(cfg_getstr(cfg_general, "color_bad")) || !valid_color(cfg_getstr(cfg_general, "color_separator")))
512 die("Bad color format");
513
514 #if YAJL_MAJOR >= 2
515 yajl_gen json_gen = yajl_gen_alloc(NULL);
516 #else
517 yajl_gen json_gen = yajl_gen_alloc(NULL, NULL);
518 #endif
519
520 if (output_format == O_I3BAR) {
521 /* Initialize the i3bar protocol. See i3/docs/i3bar-protocol
522 * for details. */
523 printf("{\"version\":1}\n[\n");
524 fflush(stdout);
525 yajl_gen_array_open(json_gen);
526 yajl_gen_clear(json_gen);
527 }
528 if (output_format == O_TERM) {
529 /* Save the cursor-position and hide the cursor */
530 printf("\033[s\033[?25l");
531 /* Undo at exit */
532 atexit(&reset_cursor);
533 }
534
535 if ((general_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
536 die("Could not create socket\n");
537
538 int interval = cfg_getint(cfg_general, "interval");
539
540 /* One memory page which each plugin can use to buffer output.
541 * Even though it’s unclean, we just assume that the user will not
542 * specify a format string which expands to something longer than 4096
543 * bytes — given that the output of i3status is used to display
544 * information on screen, more than 1024 characters for the full line
545 * (!), not individual plugins, seem very unlikely. */
546 char buffer[4096];
547
548 void **per_instance = calloc(cfg_size(cfg, "order"), sizeof(*per_instance));
549
550 while (1) {
551 if (exit_upon_signal) {
552 fprintf(stderr, "Exiting due to signal.\n");
553 exit(1);
184554 }
185 free(buf);
186
187 die("Unable to find the configuration file (looked at "
188 "~/.i3status.conf, $XDG_CONFIG_HOME/i3status/config, "
189 "/etc/i3status.conf and $XDG_CONFIG_DIRS/i3status/config)");
190 return NULL;
191 }
192
193 int main(int argc, char *argv[]) {
194 unsigned int j;
195
196 cfg_opt_t general_opts[] = {
197 CFG_STR("output_format", "auto", CFGF_NONE),
198 CFG_BOOL("colors", 1, CFGF_NONE),
199 CFG_STR("color_separator", "#333333", CFGF_NONE),
200 CFG_INT("interval", 1, CFGF_NONE),
201 CFG_COLOR_OPTS("#00FF00", "#FFFF00", "#FF0000"),
202 CFG_END()
203 };
204
205 cfg_opt_t run_watch_opts[] = {
206 CFG_STR("pidfile", NULL, CFGF_NONE),
207 CFG_STR("format", "%title: %status", CFGF_NONE),
208 CFG_CUSTOM_COLOR_OPTS,
209 CFG_END()
210 };
211
212 cfg_opt_t path_exists_opts[] = {
213 CFG_STR("path", NULL, CFGF_NONE),
214 CFG_STR("format", "%title: %status", CFGF_NONE),
215 CFG_CUSTOM_COLOR_OPTS,
216 CFG_END()
217 };
218
219 cfg_opt_t wireless_opts[] = {
220 CFG_STR("format_up", "W: (%quality at %essid, %bitrate) %ip", CFGF_NONE),
221 CFG_STR("format_down", "W: down", CFGF_NONE),
222 CFG_CUSTOM_COLOR_OPTS,
223 CFG_END()
224 };
225
226 cfg_opt_t ethernet_opts[] = {
227 CFG_STR("format_up", "E: %ip (%speed)", CFGF_NONE),
228 CFG_STR("format_down", "E: down", CFGF_NONE),
229 CFG_CUSTOM_COLOR_OPTS,
230 CFG_END()
231 };
232
233 cfg_opt_t ipv6_opts[] = {
234 CFG_STR("format_up", "%ip", CFGF_NONE),
235 CFG_STR("format_down", "no IPv6", CFGF_NONE),
236 CFG_CUSTOM_COLOR_OPTS,
237 CFG_END()
238 };
239
240 cfg_opt_t battery_opts[] = {
241 CFG_STR("format", "%status %percentage %remaining", CFGF_NONE),
242 CFG_STR("format_down", "No battery", CFGF_NONE),
243 CFG_STR("path", "/sys/class/power_supply/BAT%d/uevent", CFGF_NONE),
244 CFG_INT("low_threshold", 30, CFGF_NONE),
245 CFG_STR("threshold_type", "time", CFGF_NONE),
246 CFG_BOOL("last_full_capacity", false, CFGF_NONE),
247 CFG_BOOL("integer_battery_capacity", false, CFGF_NONE),
248 CFG_CUSTOM_COLOR_OPTS,
249 CFG_END()
250 };
251
252 cfg_opt_t time_opts[] = {
253 CFG_STR("format", "%Y-%m-%d %H:%M:%S", CFGF_NONE),
254 CFG_END()
255 };
256
257 cfg_opt_t tztime_opts[] = {
258 CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
259 CFG_STR("timezone", "", CFGF_NONE),
260 CFG_END()
261 };
262
263 cfg_opt_t ddate_opts[] = {
264 CFG_STR("format", "%{%a, %b %d%}, %Y%N - %H", CFGF_NONE),
265 CFG_END()
266 };
267
268 cfg_opt_t load_opts[] = {
269 CFG_STR("format", "%1min %5min %15min", CFGF_NONE),
270 CFG_FLOAT("max_threshold", 5, CFGF_NONE),
271 CFG_CUSTOM_COLOR_OPTS,
272 CFG_END()
273 };
274
275 cfg_opt_t usage_opts[] = {
276 CFG_STR("format", "%usage", CFGF_NONE),
277 CFG_END()
278 };
279
280 cfg_opt_t temp_opts[] = {
281 CFG_STR("format", "%degrees C", CFGF_NONE),
282 CFG_STR("path", NULL, CFGF_NONE),
283 CFG_INT("max_threshold", 75, CFGF_NONE),
284 CFG_CUSTOM_COLOR_OPTS,
285 CFG_END()
286 };
287
288 cfg_opt_t disk_opts[] = {
289 CFG_STR("format", "%free", CFGF_NONE),
290 CFG_STR("prefix_type", "binary", CFGF_NONE),
291 CFG_END()
292 };
293
294 cfg_opt_t volume_opts[] = {
295 CFG_STR("format", "♪: %volume", CFGF_NONE),
296 CFG_STR("format_muted", "♪: 0%%", CFGF_NONE),
297 CFG_STR("device", "default", CFGF_NONE),
298 CFG_STR("mixer", "Master", CFGF_NONE),
299 CFG_INT("mixer_idx", 0, CFGF_NONE),
300 CFG_CUSTOM_COLOR_OPTS,
301 CFG_END()
302 };
303
304 cfg_opt_t opts[] = {
305 CFG_STR_LIST("order", "{}", CFGF_NONE),
306 CFG_SEC("general", general_opts, CFGF_NONE),
307 CFG_SEC("run_watch", run_watch_opts, CFGF_TITLE | CFGF_MULTI),
308 CFG_SEC("path_exists", path_exists_opts, CFGF_TITLE | CFGF_MULTI),
309 CFG_SEC("wireless", wireless_opts, CFGF_TITLE | CFGF_MULTI),
310 CFG_SEC("ethernet", ethernet_opts, CFGF_TITLE | CFGF_MULTI),
311 CFG_SEC("battery", battery_opts, CFGF_TITLE | CFGF_MULTI),
312 CFG_SEC("cpu_temperature", temp_opts, CFGF_TITLE | CFGF_MULTI),
313 CFG_SEC("disk", disk_opts, CFGF_TITLE | CFGF_MULTI),
314 CFG_SEC("volume", volume_opts, CFGF_TITLE | CFGF_MULTI),
315 CFG_SEC("ipv6", ipv6_opts, CFGF_NONE),
316 CFG_SEC("time", time_opts, CFGF_NONE),
317 CFG_SEC("tztime", tztime_opts, CFGF_TITLE | CFGF_MULTI),
318 CFG_SEC("ddate", ddate_opts, CFGF_NONE),
319 CFG_SEC("load", load_opts, CFGF_NONE),
320 CFG_SEC("cpu_usage", usage_opts, CFGF_NONE),
321 CFG_CUSTOM_COLOR_OPTS,
322 CFG_END()
323 };
324
325 char *configfile = NULL;
326 int o, option_index = 0;
327 struct option long_options[] = {
328 {"config", required_argument, 0, 'c'},
329 {"help", no_argument, 0, 'h'},
330 {"version", no_argument, 0, 'v'},
331 {0, 0, 0, 0}
332 };
333
334 struct sigaction action;
335 memset(&action, 0, sizeof(struct sigaction));
336 action.sa_handler = fatalsig;
337
338 /* Exit upon SIGPIPE because when we have nowhere to write to, gathering system
339 * information is pointless. Also exit explicitly on SIGTERM and SIGINT because
340 * only this will trigger a reset of the cursor in the terminal output-format.
341 */
342 sigaction(SIGPIPE, &action, NULL);
343 sigaction(SIGTERM, &action, NULL);
344 sigaction(SIGINT, &action, NULL);
345
346 memset(&action, 0, sizeof(struct sigaction));
347 action.sa_handler = sigusr1;
348 sigaction(SIGUSR1, &action, NULL);
349
350 if (setlocale(LC_ALL, "") == NULL)
351 die("Could not set locale. Please make sure all your LC_* / LANG settings are correct.");
352
353 while ((o = getopt_long(argc, argv, "c:hv", long_options, &option_index)) != -1)
354 if ((char)o == 'c')
355 configfile = optarg;
356 else if ((char)o == 'h') {
357 printf("i3status " VERSION " © 2008-2012 Michael Stapelberg and contributors\n"
358 "Syntax: %s [-c <configfile>] [-h] [-v]\n", argv[0]);
359 return 0;
360 } else if ((char)o == 'v') {
361 printf("i3status " VERSION " © 2008-2012 Michael Stapelberg and contributors\n");
362 return 0;
363 }
364
365
366 if (configfile == NULL)
367 configfile = get_config_path();
368
369 cfg = cfg_init(opts, CFGF_NOCASE);
370 if (cfg_parse(cfg, configfile) == CFG_PARSE_ERROR)
371 return EXIT_FAILURE;
372
373 if (cfg_size(cfg, "order") == 0)
374 die("Your 'order' array is empty. Please fix your config.\n");
375
376 cfg_general = cfg_getsec(cfg, "general");
377 if (cfg_general == NULL)
378 die("Could not get section \"general\"\n");
379
380 char *output_str = cfg_getstr(cfg_general, "output_format");
381 if (strcasecmp(output_str, "auto") == 0) {
382 fprintf(stderr, "i3status: trying to auto-detect output_format setting\n");
383 output_str = auto_detect_format();
384 if (!output_str) {
385 output_str = "none";
386 fprintf(stderr, "i3status: falling back to \"none\"\n");
387 } else {
388 fprintf(stderr, "i3status: auto-detected \"%s\"\n", output_str);
389 }
555 struct timeval tv;
556 gettimeofday(&tv, NULL);
557 if (output_format == O_I3BAR)
558 yajl_gen_array_open(json_gen);
559 else if (output_format == O_TERM)
560 /* Restore the cursor-position, clear line */
561 printf("\033[u\033[K");
562 for (j = 0; j < cfg_size(cfg, "order"); j++) {
563 cur_instance = per_instance + j;
564 if (j > 0)
565 print_separator(separator);
566
567 const char *current = cfg_getnstr(cfg, "order", j);
568
569 CASE_SEC("ipv6") {
570 SEC_OPEN_MAP("ipv6");
571 print_ipv6_info(json_gen, buffer, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
572 SEC_CLOSE_MAP;
573 }
574
575 CASE_SEC_TITLE("wireless") {
576 SEC_OPEN_MAP("wireless");
577 const char *interface = NULL;
578 if (strcasecmp(title, "_first_") == 0)
579 interface = first_eth_interface(NET_TYPE_WIRELESS);
580 if (interface == NULL)
581 interface = title;
582 print_wireless_info(json_gen, buffer, interface, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
583 SEC_CLOSE_MAP;
584 }
585
586 CASE_SEC_TITLE("ethernet") {
587 SEC_OPEN_MAP("ethernet");
588 const char *interface = NULL;
589 if (strcasecmp(title, "_first_") == 0)
590 interface = first_eth_interface(NET_TYPE_ETHERNET);
591 if (interface == NULL)
592 interface = title;
593 print_eth_info(json_gen, buffer, interface, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
594 SEC_CLOSE_MAP;
595 }
596
597 CASE_SEC_TITLE("battery") {
598 SEC_OPEN_MAP("battery");
599 print_battery_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getstr(sec, "format_down"), cfg_getstr(sec, "status_chr"), cfg_getstr(sec, "status_bat"), cfg_getstr(sec, "status_full"), cfg_getint(sec, "low_threshold"), cfg_getstr(sec, "threshold_type"), cfg_getbool(sec, "last_full_capacity"), cfg_getbool(sec, "integer_battery_capacity"), cfg_getbool(sec, "hide_seconds"));
600 SEC_CLOSE_MAP;
601 }
602
603 CASE_SEC_TITLE("run_watch") {
604 SEC_OPEN_MAP("run_watch");
605 print_run_watch(json_gen, buffer, title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
606 SEC_CLOSE_MAP;
607 }
608
609 CASE_SEC_TITLE("path_exists") {
610 SEC_OPEN_MAP("path_exists");
611 print_path_exists(json_gen, buffer, title, cfg_getstr(sec, "path"), cfg_getstr(sec, "format"));
612 SEC_CLOSE_MAP;
613 }
614
615 CASE_SEC_TITLE("disk") {
616 SEC_OPEN_MAP("disk_info");
617 print_disk_info(json_gen, buffer, title, cfg_getstr(sec, "format"), cfg_getstr(sec, "format_not_mounted"), cfg_getstr(sec, "prefix_type"), cfg_getstr(sec, "threshold_type"), cfg_getfloat(sec, "low_threshold"));
618 SEC_CLOSE_MAP;
619 }
620
621 CASE_SEC("load") {
622 SEC_OPEN_MAP("load");
623 print_load(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getfloat(sec, "max_threshold"));
624 SEC_CLOSE_MAP;
625 }
626
627 CASE_SEC("time") {
628 SEC_OPEN_MAP("time");
629 print_time(json_gen, buffer, cfg_getstr(sec, "format"), NULL, tv.tv_sec);
630 SEC_CLOSE_MAP;
631 }
632
633 CASE_SEC_TITLE("tztime") {
634 SEC_OPEN_MAP("tztime");
635 print_time(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "timezone"), tv.tv_sec);
636 SEC_CLOSE_MAP;
637 }
638
639 CASE_SEC("ddate") {
640 SEC_OPEN_MAP("ddate");
641 print_ddate(json_gen, buffer, cfg_getstr(sec, "format"), tv.tv_sec);
642 SEC_CLOSE_MAP;
643 }
644
645 CASE_SEC_TITLE("volume") {
646 SEC_OPEN_MAP("volume");
647 print_volume(json_gen, buffer, cfg_getstr(sec, "format"),
648 cfg_getstr(sec, "format_muted"),
649 cfg_getstr(sec, "device"),
650 cfg_getstr(sec, "mixer"),
651 cfg_getint(sec, "mixer_idx"));
652 SEC_CLOSE_MAP;
653 }
654
655 CASE_SEC_TITLE("cpu_temperature") {
656 SEC_OPEN_MAP("cpu_temperature");
657 print_cpu_temperature_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getint(sec, "max_threshold"));
658 SEC_CLOSE_MAP;
659 }
660
661 CASE_SEC("cpu_usage") {
662 SEC_OPEN_MAP("cpu_usage");
663 print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"));
664 SEC_CLOSE_MAP;
665 }
390666 }
391
392 if (strcasecmp(output_str, "dzen2") == 0)
393 output_format = O_DZEN2;
394 else if (strcasecmp(output_str, "xmobar") == 0)
395 output_format = O_XMOBAR;
396 else if (strcasecmp(output_str, "i3bar") == 0)
397 output_format = O_I3BAR;
398 else if (strcasecmp(output_str, "term") == 0)
399 output_format = O_TERM;
400 else if (strcasecmp(output_str, "none") == 0)
401 output_format = O_NONE;
402 else die("Unknown output format: \"%s\"\n", output_str);
403
404 if (!valid_color(cfg_getstr(cfg_general, "color_good"))
405 || !valid_color(cfg_getstr(cfg_general, "color_degraded"))
406 || !valid_color(cfg_getstr(cfg_general, "color_bad"))
407 || !valid_color(cfg_getstr(cfg_general, "color_separator")))
408 die("Bad color format");
409
667 if (output_format == O_I3BAR) {
668 yajl_gen_array_close(json_gen);
669 const unsigned char *buf;
410670 #if YAJL_MAJOR >= 2
411 yajl_gen json_gen = yajl_gen_alloc(NULL);
671 size_t len;
412672 #else
413 yajl_gen json_gen = yajl_gen_alloc(NULL, NULL);
673 unsigned int len;
414674 #endif
415
416 if (output_format == O_I3BAR) {
417 /* Initialize the i3bar protocol. See i3/docs/i3bar-protocol
418 * for details. */
419 printf("{\"version\":1}\n[\n");
420 fflush(stdout);
421 yajl_gen_array_open(json_gen);
422 yajl_gen_clear(json_gen);
675 yajl_gen_get_buf(json_gen, &buf, &len);
676 write(STDOUT_FILENO, buf, len);
677 yajl_gen_clear(json_gen);
423678 }
424 if (output_format == O_TERM) {
425 /* Save the cursor-position and hide the cursor */
426 printf("\033[s\033[?25l");
427 /* Undo at exit */
428 atexit(&reset_cursor);
429 }
430
431 if ((general_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
432 die("Could not create socket\n");
433
434 int interval = cfg_getint(cfg_general, "interval");
435
436 /* One memory page which each plugin can use to buffer output.
437 * Even though it’s unclean, we just assume that the user will not
438 * specify a format string which expands to something longer than 4096
439 * bytes — given that the output of i3status is used to display
440 * information on screen, more than 1024 characters for the full line
441 * (!), not individual plugins, seem very unlikely. */
442 char buffer[4096];
443
444 while (1) {
445 if (exit_upon_signal) {
446 fprintf(stderr, "Exiting due to signal.\n");
447 exit(1);
448 }
449 struct timeval tv;
450 gettimeofday(&tv, NULL);
451 if (output_format == O_I3BAR)
452 yajl_gen_array_open(json_gen);
453 else if (output_format == O_TERM)
454 /* Restore the cursor-position, clear line */
455 printf("\033[u\033[K");
456 for (j = 0; j < cfg_size(cfg, "order"); j++) {
457 if (j > 0)
458 print_seperator();
459
460 const char *current = cfg_getnstr(cfg, "order", j);
461
462 CASE_SEC("ipv6") {
463 SEC_OPEN_MAP("ipv6");
464 print_ipv6_info(json_gen, buffer, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
465 SEC_CLOSE_MAP;
466 }
467
468 CASE_SEC_TITLE("wireless") {
469 SEC_OPEN_MAP("wireless");
470 print_wireless_info(json_gen, buffer, title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
471 SEC_CLOSE_MAP;
472 }
473
474 CASE_SEC_TITLE("ethernet") {
475 SEC_OPEN_MAP("ethernet");
476 print_eth_info(json_gen, buffer, title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
477 SEC_CLOSE_MAP;
478 }
479
480 CASE_SEC_TITLE("battery") {
481 SEC_OPEN_MAP("battery");
482 print_battery_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getstr(sec, "format_down"), cfg_getint(sec, "low_threshold"), cfg_getstr(sec, "threshold_type"), cfg_getbool(sec, "last_full_capacity"), cfg_getbool(sec, "integer_battery_capacity"));
483 SEC_CLOSE_MAP;
484 }
485
486 CASE_SEC_TITLE("run_watch") {
487 SEC_OPEN_MAP("run_watch");
488 print_run_watch(json_gen, buffer, title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
489 SEC_CLOSE_MAP;
490 }
491
492 CASE_SEC_TITLE("path_exists") {
493 SEC_OPEN_MAP("path_exists");
494 print_path_exists(json_gen, buffer, title, cfg_getstr(sec, "path"), cfg_getstr(sec, "format"));
495 SEC_CLOSE_MAP;
496 }
497
498 CASE_SEC_TITLE("disk") {
499 SEC_OPEN_MAP("disk_info");
500 print_disk_info(json_gen, buffer, title, cfg_getstr(sec, "format"), cfg_getstr(sec, "prefix_type"));
501 SEC_CLOSE_MAP;
502 }
503
504 CASE_SEC("load") {
505 SEC_OPEN_MAP("load");
506 print_load(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getfloat(sec, "max_threshold"));
507 SEC_CLOSE_MAP;
508 }
509
510 CASE_SEC("time") {
511 SEC_OPEN_MAP("time");
512 print_time(json_gen, buffer, cfg_getstr(sec, "format"), NULL, tv.tv_sec);
513 SEC_CLOSE_MAP;
514 }
515
516 CASE_SEC_TITLE("tztime") {
517 SEC_OPEN_MAP("tztime");
518 print_time(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "timezone"), tv.tv_sec);
519 SEC_CLOSE_MAP;
520 }
521
522 CASE_SEC("ddate") {
523 SEC_OPEN_MAP("ddate");
524 print_ddate(json_gen, buffer, cfg_getstr(sec, "format"), tv.tv_sec);
525 SEC_CLOSE_MAP;
526 }
527
528 CASE_SEC_TITLE("volume") {
529 SEC_OPEN_MAP("volume");
530 print_volume(json_gen, buffer, cfg_getstr(sec, "format"),
531 cfg_getstr(sec, "format_muted"),
532 cfg_getstr(sec, "device"),
533 cfg_getstr(sec, "mixer"),
534 cfg_getint(sec, "mixer_idx"));
535 SEC_CLOSE_MAP;
536 }
537
538 CASE_SEC_TITLE("cpu_temperature") {
539 SEC_OPEN_MAP("cpu_temperature");
540 print_cpu_temperature_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getint(sec, "max_threshold"));
541 SEC_CLOSE_MAP;
542 }
543
544 CASE_SEC("cpu_usage") {
545 SEC_OPEN_MAP("cpu_usage");
546 print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"));
547 SEC_CLOSE_MAP;
548 }
549 }
550 if (output_format == O_I3BAR) {
551 yajl_gen_array_close(json_gen);
552 const unsigned char *buf;
553 #if YAJL_MAJOR >= 2
554 size_t len;
555 #else
556 unsigned int len;
557 #endif
558 yajl_gen_get_buf(json_gen, &buf, &len);
559 write(STDOUT_FILENO, buf, len);
560 yajl_gen_clear(json_gen);
561 }
562
563 printf("\n");
564 fflush(stdout);
565
566 /* To provide updates on every full second (as good as possible)
567 * we don’t use sleep(interval) but we sleep until the next
568 * second (with microsecond precision) plus (interval-1)
569 * seconds. We also align to 60 seconds modulo interval such
570 * that we start with :00 on every new minute. */
571 struct timeval current_timeval;
572 gettimeofday(&current_timeval, NULL);
573 struct timespec ts = {interval - 1 - (current_timeval.tv_sec % interval), (10e5 - current_timeval.tv_usec) * 1000};
574 nanosleep(&ts, NULL);
575 }
576 }
679
680 printf("\n");
681 fflush(stdout);
682
683 /* To provide updates on every full second (as good as possible)
684 * we don’t use sleep(interval) but we sleep until the next
685 * second (with microsecond precision) plus (interval-1)
686 * seconds. We also align to 60 seconds modulo interval such
687 * that we start with :00 on every new minute. */
688 struct timeval current_timeval;
689 gettimeofday(&current_timeval, NULL);
690 struct timespec ts = {interval - 1 - (current_timeval.tv_sec % interval), (10e5 - current_timeval.tv_usec) * 1000};
691 nanosleep(&ts, NULL);
692 }
693 }
1414 order += "disk /"
1515 order += "run_watch DHCP"
1616 order += "run_watch VPN"
17 order += "wireless wlan0"
18 order += "ethernet eth0"
17 order += "wireless _first_"
18 order += "ethernet _first_"
1919 order += "battery 0"
2020 order += "load"
2121 order += "tztime local"
2222
23 wireless wlan0 {
23 wireless _first_ {
2424 format_up = "W: (%quality at %essid) %ip"
2525 format_down = "W: down"
2626 }
2727
28 ethernet eth0 {
28 ethernet _first_ {
2929 # if you use %speed, i3status requires root privileges
3030 format_up = "E: %ip (%speed)"
3131 format_down = "E: down"
00 #ifndef _I3STATUS_H
11 #define _I3STATUS_H
22
3 enum { O_DZEN2, O_XMOBAR, O_I3BAR, O_TERM, O_NONE } output_format;
3 enum { O_DZEN2,
4 O_XMOBAR,
5 O_I3BAR,
6 O_TERM,
7 O_NONE } output_format;
48
59 #include <stdbool.h>
610 #include <confuse.h>
2933 #define BATT_TIME "hw.acpi.battery.time"
3034 #define BATT_STATE "hw.acpi.battery.state"
3135
32 #elif defined(__OpenBSD__)
36 #elif defined(__OpenBSD__) || defined(__NetBSD__)
3337 /* Default to acpitz(4) if no path is set. */
3438 #define THERMAL_ZONE "acpitz%d"
35 #elif defined(__NetBSD__)
36 /* Rely on envsys(4). The key of the sensor is generally cpu%d temperature */
37 #define THERMAL_ZONE "cpu%d temperature"
3839 #endif
3940
4041 #if defined(__FreeBSD_kernel__) && defined(__GLIBC__)
4748 /* Allows for the definition of a variable without opening a new scope, thus
4849 * suited for usage in a macro. Idea from wmii. */
4950 #define with(type, var, init) \
50 for (type var = (type)-1; (var == (type)-1) && ((var=(init)) || 1); )
51
52 #define CASE_SEC(name) \
53 if (BEGINS_WITH(current, name)) \
54 with(cfg_t *, sec, cfg_section = cfg_getsec(cfg, name)) \
55 if (sec != NULL)
56
57 #define CASE_SEC_TITLE(name) \
58 if (BEGINS_WITH(current, name)) \
59 with(const char *, title, current + strlen(name) + 1) \
60 with(cfg_t *, sec, cfg_section = cfg_gettsec(cfg, name, title)) \
61 if (sec != NULL)
51 for (type var = (type)-1; (var == (type)-1) && ((var = (init)) || 1);)
52
53 #define CASE_SEC(name) \
54 if (BEGINS_WITH(current, name)) \
55 with(cfg_t *, sec, cfg_section = cfg_getsec(cfg, name)) if (sec != NULL)
56
57 #define CASE_SEC_TITLE(name) \
58 if (BEGINS_WITH(current, name)) \
59 with(const char *, title, current + strlen(name) + 1) \
60 with(cfg_t *, sec, cfg_section = cfg_gettsec(cfg, name, title)) if (sec != NULL)
6261
6362 /* Macro which any plugin can use to output the full_text part (when the output
6463 * format is JSON) or just output to stdout (any other output format). */
65 #define OUTPUT_FULL_TEXT(text) \
66 do { \
67 /* Terminate the output buffer here in any case, so that it’s \
68 * not forgotten in the module */ \
69 *outwalk = '\0'; \
70 if (output_format == O_I3BAR) { \
71 yajl_gen_string(json_gen, (const unsigned char *)"full_text", strlen("full_text")); \
72 yajl_gen_string(json_gen, (const unsigned char *)text, strlen(text)); \
73 } else { \
74 printf("%s", text); \
75 } \
76 } while (0)
77
78 #define SEC_OPEN_MAP(name) \
79 do { \
80 if (output_format == O_I3BAR) { \
81 yajl_gen_map_open(json_gen); \
82 yajl_gen_string(json_gen, (const unsigned char *)"name", strlen("name")); \
83 yajl_gen_string(json_gen, (const unsigned char *)name, strlen(name)); \
84 } \
85 } while (0)
86
87 #define SEC_CLOSE_MAP \
88 do { \
89 if (output_format == O_I3BAR) { \
90 yajl_gen_map_close(json_gen); \
91 } \
92 } while (0)
93
94 #define START_COLOR(colorstr) \
95 do { \
96 if (cfg_getbool(cfg_general, "colors")) { \
97 const char *_val = NULL; \
98 if (cfg_section) \
99 _val = cfg_getstr(cfg_section, colorstr); \
100 if (!_val) \
101 _val = cfg_getstr(cfg_general, colorstr); \
102 if (output_format == O_I3BAR) { \
103 yajl_gen_string(json_gen, (const unsigned char *)"color", strlen("color")); \
104 yajl_gen_string(json_gen, (const unsigned char *)_val, strlen(_val)); \
105 } else { \
106 outwalk += sprintf(outwalk, "%s", color(colorstr)); \
107 } \
108 } \
109 } while (0)
110
111 #define END_COLOR \
112 do { \
113 if (cfg_getbool(cfg_general, "colors") && output_format != O_I3BAR) { \
114 outwalk += sprintf(outwalk, "%s", endcolor()); \
115 } \
116 } while (0)
117
118 #define INSTANCE(instance) \
119 do { \
120 if (output_format == O_I3BAR) { \
121 yajl_gen_string(json_gen, (const unsigned char *)"instance", strlen("instance")); \
122 yajl_gen_string(json_gen, (const unsigned char *)instance, strlen(instance)); \
123 } \
124 } while (0)
125
126
127 typedef enum { CS_DISCHARGING, CS_CHARGING, CS_FULL } charging_status_t;
64 #define OUTPUT_FULL_TEXT(text) \
65 do { \
66 /* Terminate the output buffer here in any case, so that it’s \
67 * not forgotten in the module */ \
68 *outwalk = '\0'; \
69 if (output_format == O_I3BAR) { \
70 yajl_gen_string(json_gen, (const unsigned char *) "full_text", strlen("full_text")); \
71 yajl_gen_string(json_gen, (const unsigned char *)text, strlen(text)); \
72 } else { \
73 printf("%s", text); \
74 } \
75 } while (0)
76
77 #define SEC_OPEN_MAP(name) \
78 do { \
79 if (output_format == O_I3BAR) { \
80 yajl_gen_map_open(json_gen); \
81 yajl_gen_string(json_gen, (const unsigned char *) "name", strlen("name")); \
82 yajl_gen_string(json_gen, (const unsigned char *)name, strlen(name)); \
83 } \
84 } while (0)
85
86 #define SEC_CLOSE_MAP \
87 do { \
88 if (output_format == O_I3BAR) { \
89 char *_align = cfg_getstr(sec, "align"); \
90 if (_align) { \
91 yajl_gen_string(json_gen, (const unsigned char *) "align", strlen("align")); \
92 yajl_gen_string(json_gen, (const unsigned char *)_align, strlen(_align)); \
93 } \
94 struct min_width *_width = cfg_getptr(sec, "min_width"); \
95 if (_width) { \
96 /* if the value can be parsed as a number, we use the numerical value */ \
97 if (_width->num > 0) { \
98 yajl_gen_string(json_gen, (const unsigned char *) "min_width", strlen("min_width")); \
99 yajl_gen_integer(json_gen, _width->num); \
100 } else { \
101 yajl_gen_string(json_gen, (const unsigned char *) "min_width", strlen("min_width")); \
102 yajl_gen_string(json_gen, (const unsigned char *)_width->str, strlen(_width->str)); \
103 } \
104 } \
105 const char *_sep = cfg_getstr(cfg_general, "separator"); \
106 if (strlen(_sep) == 0) { \
107 yajl_gen_string(json_gen, (const unsigned char *) "separator", strlen("separator")); \
108 yajl_gen_bool(json_gen, false); \
109 } \
110 yajl_gen_map_close(json_gen); \
111 } \
112 } while (0)
113
114 #define START_COLOR(colorstr) \
115 do { \
116 if (cfg_getbool(cfg_general, "colors")) { \
117 const char *_val = NULL; \
118 if (cfg_section) \
119 _val = cfg_getstr(cfg_section, colorstr); \
120 if (!_val) \
121 _val = cfg_getstr(cfg_general, colorstr); \
122 if (output_format == O_I3BAR) { \
123 yajl_gen_string(json_gen, (const unsigned char *) "color", strlen("color")); \
124 yajl_gen_string(json_gen, (const unsigned char *)_val, strlen(_val)); \
125 } else { \
126 outwalk += sprintf(outwalk, "%s", color(colorstr)); \
127 } \
128 } \
129 } while (0)
130
131 #define END_COLOR \
132 do { \
133 if (cfg_getbool(cfg_general, "colors") && output_format != O_I3BAR) { \
134 outwalk += sprintf(outwalk, "%s", endcolor()); \
135 } \
136 } while (0)
137
138 #define INSTANCE(instance) \
139 do { \
140 if (output_format == O_I3BAR) { \
141 yajl_gen_string(json_gen, (const unsigned char *) "instance", strlen("instance")); \
142 yajl_gen_string(json_gen, (const unsigned char *)instance, strlen(instance)); \
143 } \
144 } while (0)
145
146 typedef enum { CS_DISCHARGING,
147 CS_CHARGING,
148 CS_FULL } charging_status_t;
149
150 /*
151 * The "min_width" module option may either be defined as a string or a number.
152 */
153 struct min_width {
154 long num;
155 const char *str;
156 };
128157
129158 /* src/general.c */
130159 char *skip_character(char *input, char character, int amount);
132161 bool slurp(const char *filename, char *destination, int size);
133162
134163 /* src/output.c */
135 void print_seperator();
164 void print_separator(const char *separator);
136165 char *color(const char *colorstr);
137 char *endcolor() __attribute__ ((pure));
166 char *endcolor() __attribute__((pure));
138167 void reset_cursor(void);
139168
140169 /* src/auto_detect_format.c */
143172 /* src/print_time.c */
144173 void set_timezone(const char *tz);
145174
175 /* src/first_network_device.c */
176 typedef enum {
177 NET_TYPE_WIRELESS = 0,
178 NET_TYPE_ETHERNET = 1
179 } net_type_t;
180 const char *first_eth_interface(const net_type_t type);
181
146182 void print_ipv6_info(yajl_gen json_gen, char *buffer, const char *format_up, const char *format_down);
147 void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format, const char *prefix_type);
148 void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity);
183 void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format, const char *format_not_mounted, const char *prefix_type, const char *threshold_type, const double low_threshold);
184 void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, const char *status_chr, const char *status_bat, const char *status_full, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity, bool hide_seconds);
149185 void print_time(yajl_gen json_gen, char *buffer, const char *format, const char *tz, time_t t);
150186 void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t);
151187 const char *get_ip_addr();
164200
165201 extern cfg_t *cfg, *cfg_general, *cfg_section;
166202
167 #endif
203 extern void **cur_instance;
204
205 #endif
3131 * @(#)queue.h 8.5 (Berkeley) 8/20/94
3232 */
3333
34 #ifndef _SYS_QUEUE_H_
35 #define _SYS_QUEUE_H_
34 #ifndef _SYS_QUEUE_H_
35 #define _SYS_QUEUE_H_
3636
3737 /*
3838 * This file defines five types of data structures: singly-linked lists,
9090 /*
9191 * Singly-linked List definitions.
9292 */
93 #define SLIST_HEAD(name, type) \
94 struct name { \
95 struct type *slh_first; /* first element */ \
96 }
97
98 #define SLIST_HEAD_INITIALIZER(head) \
99 { NULL }
100
101 #define SLIST_ENTRY(type) \
102 struct { \
103 struct type *sle_next; /* next element */ \
104 }
93 #define SLIST_HEAD(name, type) \
94 struct name { \
95 struct type *slh_first; /* first element */ \
96 }
97
98 #define SLIST_HEAD_INITIALIZER(head) \
99 { NULL }
100
101 #define SLIST_ENTRY(type) \
102 struct { \
103 struct type *sle_next; /* next element */ \
104 }
105105
106106 /*
107107 * Singly-linked List access methods.
108108 */
109 #define SLIST_FIRST(head) ((head)->slh_first)
110 #define SLIST_END(head) NULL
111 #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
112 #define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
113
114 #define SLIST_FOREACH(var, head, field) \
115 for((var) = SLIST_FIRST(head); \
116 (var) != SLIST_END(head); \
117 (var) = SLIST_NEXT(var, field))
118
119 #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
120 for ((varp) = &SLIST_FIRST((head)); \
121 ((var) = *(varp)) != SLIST_END(head); \
122 (varp) = &SLIST_NEXT((var), field))
109 #define SLIST_FIRST(head) ((head)->slh_first)
110 #define SLIST_END(head) NULL
111 #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
112 #define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
113
114 #define SLIST_FOREACH(var, head, field) \
115 for ((var) = SLIST_FIRST(head); \
116 (var) != SLIST_END(head); \
117 (var) = SLIST_NEXT(var, field))
118
119 #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
120 for ((varp) = &SLIST_FIRST((head)); \
121 ((var) = *(varp)) != SLIST_END(head); \
122 (varp) = &SLIST_NEXT((var), field))
123123
124124 /*
125125 * Singly-linked List functions.
126126 */
127 #define SLIST_INIT(head) { \
128 SLIST_FIRST(head) = SLIST_END(head); \
129 }
130
131 #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
132 (elm)->field.sle_next = (slistelm)->field.sle_next; \
133 (slistelm)->field.sle_next = (elm); \
134 } while (0)
135
136 #define SLIST_INSERT_HEAD(head, elm, field) do { \
137 (elm)->field.sle_next = (head)->slh_first; \
138 (head)->slh_first = (elm); \
139 } while (0)
140
141 #define SLIST_REMOVE_NEXT(head, elm, field) do { \
142 (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
143 } while (0)
144
145 #define SLIST_REMOVE_HEAD(head, field) do { \
146 (head)->slh_first = (head)->slh_first->field.sle_next; \
147 } while (0)
148
149 #define SLIST_REMOVE(head, elm, type, field) do { \
150 if ((head)->slh_first == (elm)) { \
151 SLIST_REMOVE_HEAD((head), field); \
152 } else { \
153 struct type *curelm = (head)->slh_first; \
154 \
155 while (curelm->field.sle_next != (elm)) \
156 curelm = curelm->field.sle_next; \
157 curelm->field.sle_next = \
158 curelm->field.sle_next->field.sle_next; \
159 _Q_INVALIDATE((elm)->field.sle_next); \
160 } \
161 } while (0)
127 #define SLIST_INIT(head) \
128 { \
129 SLIST_FIRST(head) = SLIST_END(head); \
130 }
131
132 #define SLIST_INSERT_AFTER(slistelm, elm, field) \
133 do { \
134 (elm)->field.sle_next = (slistelm)->field.sle_next; \
135 (slistelm)->field.sle_next = (elm); \
136 } while (0)
137
138 #define SLIST_INSERT_HEAD(head, elm, field) \
139 do { \
140 (elm)->field.sle_next = (head)->slh_first; \
141 (head)->slh_first = (elm); \
142 } while (0)
143
144 #define SLIST_REMOVE_NEXT(head, elm, field) \
145 do { \
146 (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
147 } while (0)
148
149 #define SLIST_REMOVE_HEAD(head, field) \
150 do { \
151 (head)->slh_first = (head)->slh_first->field.sle_next; \
152 } while (0)
153
154 #define SLIST_REMOVE(head, elm, type, field) \
155 do { \
156 if ((head)->slh_first == (elm)) { \
157 SLIST_REMOVE_HEAD((head), field); \
158 } else { \
159 struct type *curelm = (head)->slh_first; \
160 \
161 while (curelm->field.sle_next != (elm)) \
162 curelm = curelm->field.sle_next; \
163 curelm->field.sle_next = curelm->field.sle_next->field.sle_next; \
164 _Q_INVALIDATE((elm)->field.sle_next); \
165 } \
166 } while (0)
162167
163168 /*
164169 * List definitions.
165170 */
166 #define LIST_HEAD(name, type) \
167 struct name { \
168 struct type *lh_first; /* first element */ \
169 }
170
171 #define LIST_HEAD_INITIALIZER(head) \
172 { NULL }
173
174 #define LIST_ENTRY(type) \
175 struct { \
176 struct type *le_next; /* next element */ \
177 struct type **le_prev; /* address of previous next element */ \
178 }
171 #define LIST_HEAD(name, type) \
172 struct name { \
173 struct type *lh_first; /* first element */ \
174 }
175
176 #define LIST_HEAD_INITIALIZER(head) \
177 { NULL }
178
179 #define LIST_ENTRY(type) \
180 struct { \
181 struct type *le_next; /* next element */ \
182 struct type **le_prev; /* address of previous next element */ \
183 }
179184
180185 /*
181186 * List access methods
182187 */
183 #define LIST_FIRST(head) ((head)->lh_first)
184 #define LIST_END(head) NULL
185 #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
186 #define LIST_NEXT(elm, field) ((elm)->field.le_next)
187
188 #define LIST_FOREACH(var, head, field) \
189 for((var) = LIST_FIRST(head); \
190 (var)!= LIST_END(head); \
191 (var) = LIST_NEXT(var, field))
188 #define LIST_FIRST(head) ((head)->lh_first)
189 #define LIST_END(head) NULL
190 #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
191 #define LIST_NEXT(elm, field) ((elm)->field.le_next)
192
193 #define LIST_FOREACH(var, head, field) \
194 for ((var) = LIST_FIRST(head); \
195 (var) != LIST_END(head); \
196 (var) = LIST_NEXT(var, field))
192197
193198 /*
194199 * List functions.
195200 */
196 #define LIST_INIT(head) do { \
197 LIST_FIRST(head) = LIST_END(head); \
198 } while (0)
199
200 #define LIST_INSERT_AFTER(listelm, elm, field) do { \
201 if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
202 (listelm)->field.le_next->field.le_prev = \
203 &(elm)->field.le_next; \
204 (listelm)->field.le_next = (elm); \
205 (elm)->field.le_prev = &(listelm)->field.le_next; \
206 } while (0)
207
208 #define LIST_INSERT_BEFORE(listelm, elm, field) do { \
209 (elm)->field.le_prev = (listelm)->field.le_prev; \
210 (elm)->field.le_next = (listelm); \
211 *(listelm)->field.le_prev = (elm); \
212 (listelm)->field.le_prev = &(elm)->field.le_next; \
213 } while (0)
214
215 #define LIST_INSERT_HEAD(head, elm, field) do { \
216 if (((elm)->field.le_next = (head)->lh_first) != NULL) \
217 (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
218 (head)->lh_first = (elm); \
219 (elm)->field.le_prev = &(head)->lh_first; \
220 } while (0)
221
222 #define LIST_REMOVE(elm, field) do { \
223 if ((elm)->field.le_next != NULL) \
224 (elm)->field.le_next->field.le_prev = \
225 (elm)->field.le_prev; \
226 *(elm)->field.le_prev = (elm)->field.le_next; \
227 _Q_INVALIDATE((elm)->field.le_prev); \
228 _Q_INVALIDATE((elm)->field.le_next); \
229 } while (0)
230
231 #define LIST_REPLACE(elm, elm2, field) do { \
232 if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
233 (elm2)->field.le_next->field.le_prev = \
234 &(elm2)->field.le_next; \
235 (elm2)->field.le_prev = (elm)->field.le_prev; \
236 *(elm2)->field.le_prev = (elm2); \
237 _Q_INVALIDATE((elm)->field.le_prev); \
238 _Q_INVALIDATE((elm)->field.le_next); \
239 } while (0)
201 #define LIST_INIT(head) \
202 do { \
203 LIST_FIRST(head) = LIST_END(head); \
204 } while (0)
205
206 #define LIST_INSERT_AFTER(listelm, elm, field) \
207 do { \
208 if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
209 (listelm)->field.le_next->field.le_prev = &(elm)->field.le_next; \
210 (listelm)->field.le_next = (elm); \
211 (elm)->field.le_prev = &(listelm)->field.le_next; \
212 } while (0)
213
214 #define LIST_INSERT_BEFORE(listelm, elm, field) \
215 do { \
216 (elm)->field.le_prev = (listelm)->field.le_prev; \
217 (elm)->field.le_next = (listelm); \
218 *(listelm)->field.le_prev = (elm); \
219 (listelm)->field.le_prev = &(elm)->field.le_next; \
220 } while (0)
221
222 #define LIST_INSERT_HEAD(head, elm, field) \
223 do { \
224 if (((elm)->field.le_next = (head)->lh_first) != NULL) \
225 (head)->lh_first->field.le_prev = &(elm)->field.le_next; \
226 (head)->lh_first = (elm); \
227 (elm)->field.le_prev = &(head)->lh_first; \
228 } while (0)
229
230 #define LIST_REMOVE(elm, field) \
231 do { \
232 if ((elm)->field.le_next != NULL) \
233 (elm)->field.le_next->field.le_prev = (elm)->field.le_prev; \
234 *(elm)->field.le_prev = (elm)->field.le_next; \
235 _Q_INVALIDATE((elm)->field.le_prev); \
236 _Q_INVALIDATE((elm)->field.le_next); \
237 } while (0)
238
239 #define LIST_REPLACE(elm, elm2, field) \
240 do { \
241 if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
242 (elm2)->field.le_next->field.le_prev = &(elm2)->field.le_next; \
243 (elm2)->field.le_prev = (elm)->field.le_prev; \
244 *(elm2)->field.le_prev = (elm2); \
245 _Q_INVALIDATE((elm)->field.le_prev); \
246 _Q_INVALIDATE((elm)->field.le_next); \
247 } while (0)
240248
241249 /*
242250 * Simple queue definitions.
243251 */
244 #define SIMPLEQ_HEAD(name, type) \
245 struct name { \
246 struct type *sqh_first; /* first element */ \
247 struct type **sqh_last; /* addr of last next element */ \
248 }
249
250 #define SIMPLEQ_HEAD_INITIALIZER(head) \
251 { NULL, &(head).sqh_first }
252
253 #define SIMPLEQ_ENTRY(type) \
254 struct { \
255 struct type *sqe_next; /* next element */ \
256 }
252 #define SIMPLEQ_HEAD(name, type) \
253 struct name { \
254 struct type *sqh_first; /* first element */ \
255 struct type **sqh_last; /* addr of last next element */ \
256 }
257
258 #define SIMPLEQ_HEAD_INITIALIZER(head) \
259 { NULL, &(head).sqh_first }
260
261 #define SIMPLEQ_ENTRY(type) \
262 struct { \
263 struct type *sqe_next; /* next element */ \
264 }
257265
258266 /*
259267 * Simple queue access methods.
260268 */
261 #define SIMPLEQ_FIRST(head) ((head)->sqh_first)
262 #define SIMPLEQ_END(head) NULL
263 #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
264 #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
265
266 #define SIMPLEQ_FOREACH(var, head, field) \
267 for((var) = SIMPLEQ_FIRST(head); \
268 (var) != SIMPLEQ_END(head); \
269 (var) = SIMPLEQ_NEXT(var, field))
269 #define SIMPLEQ_FIRST(head) ((head)->sqh_first)
270 #define SIMPLEQ_END(head) NULL
271 #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
272 #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
273
274 #define SIMPLEQ_FOREACH(var, head, field) \
275 for ((var) = SIMPLEQ_FIRST(head); \
276 (var) != SIMPLEQ_END(head); \
277 (var) = SIMPLEQ_NEXT(var, field))
270278
271279 /*
272280 * Simple queue functions.
273281 */
274 #define SIMPLEQ_INIT(head) do { \
275 (head)->sqh_first = NULL; \
276 (head)->sqh_last = &(head)->sqh_first; \
277 } while (0)
278
279 #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
280 if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
281 (head)->sqh_last = &(elm)->field.sqe_next; \
282 (head)->sqh_first = (elm); \
283 } while (0)
284
285 #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
286 (elm)->field.sqe_next = NULL; \
287 *(head)->sqh_last = (elm); \
288 (head)->sqh_last = &(elm)->field.sqe_next; \
289 } while (0)
290
291 #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
292 if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
293 (head)->sqh_last = &(elm)->field.sqe_next; \
294 (listelm)->field.sqe_next = (elm); \
295 } while (0)
296
297 #define SIMPLEQ_REMOVE_HEAD(head, field) do { \
298 if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
299 (head)->sqh_last = &(head)->sqh_first; \
300 } while (0)
282 #define SIMPLEQ_INIT(head) \
283 do { \
284 (head)->sqh_first = NULL; \
285 (head)->sqh_last = &(head)->sqh_first; \
286 } while (0)
287
288 #define SIMPLEQ_INSERT_HEAD(head, elm, field) \
289 do { \
290 if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
291 (head)->sqh_last = &(elm)->field.sqe_next; \
292 (head)->sqh_first = (elm); \
293 } while (0)
294
295 #define SIMPLEQ_INSERT_TAIL(head, elm, field) \
296 do { \
297 (elm)->field.sqe_next = NULL; \
298 *(head)->sqh_last = (elm); \
299 (head)->sqh_last = &(elm)->field.sqe_next; \
300 } while (0)
301
302 #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) \
303 do { \
304 if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \
305 (head)->sqh_last = &(elm)->field.sqe_next; \
306 (listelm)->field.sqe_next = (elm); \
307 } while (0)
308
309 #define SIMPLEQ_REMOVE_HEAD(head, field) \
310 do { \
311 if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
312 (head)->sqh_last = &(head)->sqh_first; \
313 } while (0)
301314
302315 /*
303316 * Tail queue definitions.
304317 */
305 #define TAILQ_HEAD(name, type) \
306 struct name { \
307 struct type *tqh_first; /* first element */ \
308 struct type **tqh_last; /* addr of last next element */ \
309 }
310
311 #define TAILQ_HEAD_INITIALIZER(head) \
312 { NULL, &(head).tqh_first }
313
314 #define TAILQ_ENTRY(type) \
315 struct { \
316 struct type *tqe_next; /* next element */ \
317 struct type **tqe_prev; /* address of previous next element */ \
318 }
318 #define TAILQ_HEAD(name, type) \
319 struct name { \
320 struct type *tqh_first; /* first element */ \
321 struct type **tqh_last; /* addr of last next element */ \
322 }
323
324 #define TAILQ_HEAD_INITIALIZER(head) \
325 { NULL, &(head).tqh_first }
326
327 #define TAILQ_ENTRY(type) \
328 struct { \
329 struct type *tqe_next; /* next element */ \
330 struct type **tqe_prev; /* address of previous next element */ \
331 }
319332
320333 /*
321334 * tail queue access methods
322335 */
323 #define TAILQ_FIRST(head) ((head)->tqh_first)
324 #define TAILQ_END(head) NULL
325 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
326 #define TAILQ_LAST(head, headname) \
327 (*(((struct headname *)((head)->tqh_last))->tqh_last))
336 #define TAILQ_FIRST(head) ((head)->tqh_first)
337 #define TAILQ_END(head) NULL
338 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
339 #define TAILQ_LAST(head, headname) \
340 (*(((struct headname *)((head)->tqh_last))->tqh_last))
328341 /* XXX */
329 #define TAILQ_PREV(elm, headname, field) \
330 (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
331 #define TAILQ_EMPTY(head) \
332 (TAILQ_FIRST(head) == TAILQ_END(head))
333
334 #define TAILQ_FOREACH(var, head, field) \
335 for((var) = TAILQ_FIRST(head); \
336 (var) != TAILQ_END(head); \
337 (var) = TAILQ_NEXT(var, field))
338
339 #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
340 for((var) = TAILQ_LAST(head, headname); \
341 (var) != TAILQ_END(head); \
342 (var) = TAILQ_PREV(var, headname, field))
342 #define TAILQ_PREV(elm, headname, field) \
343 (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
344 #define TAILQ_EMPTY(head) \
345 (TAILQ_FIRST(head) == TAILQ_END(head))
346
347 #define TAILQ_FOREACH(var, head, field) \
348 for ((var) = TAILQ_FIRST(head); \
349 (var) != TAILQ_END(head); \
350 (var) = TAILQ_NEXT(var, field))
351
352 #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
353 for ((var) = TAILQ_LAST(head, headname); \
354 (var) != TAILQ_END(head); \
355 (var) = TAILQ_PREV(var, headname, field))
343356
344357 /*
345358 * Tail queue functions.
346359 */
347 #define TAILQ_INIT(head) do { \
348 (head)->tqh_first = NULL; \
349 (head)->tqh_last = &(head)->tqh_first; \
350 } while (0)
351
352 #define TAILQ_INSERT_HEAD(head, elm, field) do { \
353 if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
354 (head)->tqh_first->field.tqe_prev = \
355 &(elm)->field.tqe_next; \
356 else \
357 (head)->tqh_last = &(elm)->field.tqe_next; \
358 (head)->tqh_first = (elm); \
359 (elm)->field.tqe_prev = &(head)->tqh_first; \
360 } while (0)
361
362 #define TAILQ_INSERT_TAIL(head, elm, field) do { \
363 (elm)->field.tqe_next = NULL; \
364 (elm)->field.tqe_prev = (head)->tqh_last; \
365 *(head)->tqh_last = (elm); \
366 (head)->tqh_last = &(elm)->field.tqe_next; \
367 } while (0)
368
369 #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
370 if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
371 (elm)->field.tqe_next->field.tqe_prev = \
372 &(elm)->field.tqe_next; \
373 else \
374 (head)->tqh_last = &(elm)->field.tqe_next; \
375 (listelm)->field.tqe_next = (elm); \
376 (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
377 } while (0)
378
379 #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
380 (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
381 (elm)->field.tqe_next = (listelm); \
382 *(listelm)->field.tqe_prev = (elm); \
383 (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
384 } while (0)
385
386 #define TAILQ_REMOVE(head, elm, field) do { \
387 if (((elm)->field.tqe_next) != NULL) \
388 (elm)->field.tqe_next->field.tqe_prev = \
389 (elm)->field.tqe_prev; \
390 else \
391 (head)->tqh_last = (elm)->field.tqe_prev; \
392 *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
393 _Q_INVALIDATE((elm)->field.tqe_prev); \
394 _Q_INVALIDATE((elm)->field.tqe_next); \
395 } while (0)
396
397 #define TAILQ_REPLACE(head, elm, elm2, field) do { \
398 if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
399 (elm2)->field.tqe_next->field.tqe_prev = \
400 &(elm2)->field.tqe_next; \
401 else \
402 (head)->tqh_last = &(elm2)->field.tqe_next; \
403 (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
404 *(elm2)->field.tqe_prev = (elm2); \
405 _Q_INVALIDATE((elm)->field.tqe_prev); \
406 _Q_INVALIDATE((elm)->field.tqe_next); \
407 } while (0)
360 #define TAILQ_INIT(head) \
361 do { \
362 (head)->tqh_first = NULL; \
363 (head)->tqh_last = &(head)->tqh_first; \
364 } while (0)
365
366 #define TAILQ_INSERT_HEAD(head, elm, field) \
367 do { \
368 if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
369 (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
370 else \
371 (head)->tqh_last = &(elm)->field.tqe_next; \
372 (head)->tqh_first = (elm); \
373 (elm)->field.tqe_prev = &(head)->tqh_first; \
374 } while (0)
375
376 #define TAILQ_INSERT_TAIL(head, elm, field) \
377 do { \
378 (elm)->field.tqe_next = NULL; \
379 (elm)->field.tqe_prev = (head)->tqh_last; \
380 *(head)->tqh_last = (elm); \
381 (head)->tqh_last = &(elm)->field.tqe_next; \
382 } while (0)
383
384 #define TAILQ_INSERT_AFTER(head, listelm, elm, field) \
385 do { \
386 if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL) \
387 (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next; \
388 else \
389 (head)->tqh_last = &(elm)->field.tqe_next; \
390 (listelm)->field.tqe_next = (elm); \
391 (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
392 } while (0)
393
394 #define TAILQ_INSERT_BEFORE(listelm, elm, field) \
395 do { \
396 (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
397 (elm)->field.tqe_next = (listelm); \
398 *(listelm)->field.tqe_prev = (elm); \
399 (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
400 } while (0)
401
402 #define TAILQ_REMOVE(head, elm, field) \
403 do { \
404 if (((elm)->field.tqe_next) != NULL) \
405 (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
406 else \
407 (head)->tqh_last = (elm)->field.tqe_prev; \
408 *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
409 _Q_INVALIDATE((elm)->field.tqe_prev); \
410 _Q_INVALIDATE((elm)->field.tqe_next); \
411 } while (0)
412
413 #define TAILQ_REPLACE(head, elm, elm2, field) \
414 do { \
415 if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
416 (elm2)->field.tqe_next->field.tqe_prev = &(elm2)->field.tqe_next; \
417 else \
418 (head)->tqh_last = &(elm2)->field.tqe_next; \
419 (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
420 *(elm2)->field.tqe_prev = (elm2); \
421 _Q_INVALIDATE((elm)->field.tqe_prev); \
422 _Q_INVALIDATE((elm)->field.tqe_next); \
423 } while (0)
408424
409425 /*
410426 * Circular queue definitions.
411427 */
412 #define CIRCLEQ_HEAD(name, type) \
413 struct name { \
414 struct type *cqh_first; /* first element */ \
415 struct type *cqh_last; /* last element */ \
416 }
417
418 #define CIRCLEQ_HEAD_INITIALIZER(head) \
419 { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
420
421 #define CIRCLEQ_ENTRY(type) \
422 struct { \
423 struct type *cqe_next; /* next element */ \
424 struct type *cqe_prev; /* previous element */ \
425 }
428 #define CIRCLEQ_HEAD(name, type) \
429 struct name { \
430 struct type *cqh_first; /* first element */ \
431 struct type *cqh_last; /* last element */ \
432 }
433
434 #define CIRCLEQ_HEAD_INITIALIZER(head) \
435 { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
436
437 #define CIRCLEQ_ENTRY(type) \
438 struct { \
439 struct type *cqe_next; /* next element */ \
440 struct type *cqe_prev; /* previous element */ \
441 }
426442
427443 /*
428444 * Circular queue access methods
429445 */
430 #define CIRCLEQ_FIRST(head) ((head)->cqh_first)
431 #define CIRCLEQ_LAST(head) ((head)->cqh_last)
432 #define CIRCLEQ_END(head) ((void *)(head))
433 #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
434 #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
435 #define CIRCLEQ_EMPTY(head) \
436 (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
437
438 #define CIRCLEQ_FOREACH(var, head, field) \
439 for((var) = CIRCLEQ_FIRST(head); \
440 (var) != CIRCLEQ_END(head); \
441 (var) = CIRCLEQ_NEXT(var, field))
442
443 #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
444 for((var) = CIRCLEQ_LAST(head); \
445 (var) != CIRCLEQ_END(head); \
446 (var) = CIRCLEQ_PREV(var, field))
446 #define CIRCLEQ_FIRST(head) ((head)->cqh_first)
447 #define CIRCLEQ_LAST(head) ((head)->cqh_last)
448 #define CIRCLEQ_END(head) ((void *)(head))
449 #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
450 #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
451 #define CIRCLEQ_EMPTY(head) \
452 (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
453
454 #define CIRCLEQ_FOREACH(var, head, field) \
455 for ((var) = CIRCLEQ_FIRST(head); \
456 (var) != CIRCLEQ_END(head); \
457 (var) = CIRCLEQ_NEXT(var, field))
458
459 #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
460 for ((var) = CIRCLEQ_LAST(head); \
461 (var) != CIRCLEQ_END(head); \
462 (var) = CIRCLEQ_PREV(var, field))
447463
448464 /*
449465 * Circular queue functions.
450466 */
451 #define CIRCLEQ_INIT(head) do { \
452 (head)->cqh_first = CIRCLEQ_END(head); \
453 (head)->cqh_last = CIRCLEQ_END(head); \
454 } while (0)
455
456 #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
457 (elm)->field.cqe_next = (listelm)->field.cqe_next; \
458 (elm)->field.cqe_prev = (listelm); \
459 if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
460 (head)->cqh_last = (elm); \
461 else \
462 (listelm)->field.cqe_next->field.cqe_prev = (elm); \
463 (listelm)->field.cqe_next = (elm); \
464 } while (0)
465
466 #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
467 (elm)->field.cqe_next = (listelm); \
468 (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
469 if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
470 (head)->cqh_first = (elm); \
471 else \
472 (listelm)->field.cqe_prev->field.cqe_next = (elm); \
473 (listelm)->field.cqe_prev = (elm); \
474 } while (0)
475
476 #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
477 (elm)->field.cqe_next = (head)->cqh_first; \
478 (elm)->field.cqe_prev = CIRCLEQ_END(head); \
479 if ((head)->cqh_last == CIRCLEQ_END(head)) \
480 (head)->cqh_last = (elm); \
481 else \
482 (head)->cqh_first->field.cqe_prev = (elm); \
483 (head)->cqh_first = (elm); \
484 } while (0)
485
486 #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
487 (elm)->field.cqe_next = CIRCLEQ_END(head); \
488 (elm)->field.cqe_prev = (head)->cqh_last; \
489 if ((head)->cqh_first == CIRCLEQ_END(head)) \
490 (head)->cqh_first = (elm); \
491 else \
492 (head)->cqh_last->field.cqe_next = (elm); \
493 (head)->cqh_last = (elm); \
494 } while (0)
495
496 #define CIRCLEQ_REMOVE(head, elm, field) do { \
497 if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
498 (head)->cqh_last = (elm)->field.cqe_prev; \
499 else \
500 (elm)->field.cqe_next->field.cqe_prev = \
501 (elm)->field.cqe_prev; \
502 if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
503 (head)->cqh_first = (elm)->field.cqe_next; \
504 else \
505 (elm)->field.cqe_prev->field.cqe_next = \
506 (elm)->field.cqe_next; \
507 _Q_INVALIDATE((elm)->field.cqe_prev); \
508 _Q_INVALIDATE((elm)->field.cqe_next); \
509 } while (0)
510
511 #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
512 if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
513 CIRCLEQ_END(head)) \
514 (head)->cqh_last = (elm2); \
515 else \
516 (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
517 if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
518 CIRCLEQ_END(head)) \
519 (head)->cqh_first = (elm2); \
520 else \
521 (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
522 _Q_INVALIDATE((elm)->field.cqe_prev); \
523 _Q_INVALIDATE((elm)->field.cqe_next); \
524 } while (0)
525
526 #endif /* !_SYS_QUEUE_H_ */
467 #define CIRCLEQ_INIT(head) \
468 do { \
469 (head)->cqh_first = CIRCLEQ_END(head); \
470 (head)->cqh_last = CIRCLEQ_END(head); \
471 } while (0)
472
473 #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) \
474 do { \
475 (elm)->field.cqe_next = (listelm)->field.cqe_next; \
476 (elm)->field.cqe_prev = (listelm); \
477 if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
478 (head)->cqh_last = (elm); \
479 else \
480 (listelm)->field.cqe_next->field.cqe_prev = (elm); \
481 (listelm)->field.cqe_next = (elm); \
482 } while (0)
483
484 #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) \
485 do { \
486 (elm)->field.cqe_next = (listelm); \
487 (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
488 if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
489 (head)->cqh_first = (elm); \
490 else \
491 (listelm)->field.cqe_prev->field.cqe_next = (elm); \
492 (listelm)->field.cqe_prev = (elm); \
493 } while (0)
494
495 #define CIRCLEQ_INSERT_HEAD(head, elm, field) \
496 do { \
497 (elm)->field.cqe_next = (head)->cqh_first; \
498 (elm)->field.cqe_prev = CIRCLEQ_END(head); \
499 if ((head)->cqh_last == CIRCLEQ_END(head)) \
500 (head)->cqh_last = (elm); \
501 else \
502 (head)->cqh_first->field.cqe_prev = (elm); \
503 (head)->cqh_first = (elm); \
504 } while (0)
505
506 #define CIRCLEQ_INSERT_TAIL(head, elm, field) \
507 do { \
508 (elm)->field.cqe_next = CIRCLEQ_END(head); \
509 (elm)->field.cqe_prev = (head)->cqh_last; \
510 if ((head)->cqh_first == CIRCLEQ_END(head)) \
511 (head)->cqh_first = (elm); \
512 else \
513 (head)->cqh_last->field.cqe_next = (elm); \
514 (head)->cqh_last = (elm); \
515 } while (0)
516
517 #define CIRCLEQ_REMOVE(head, elm, field) \
518 do { \
519 if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
520 (head)->cqh_last = (elm)->field.cqe_prev; \
521 else \
522 (elm)->field.cqe_next->field.cqe_prev = (elm)->field.cqe_prev; \
523 if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
524 (head)->cqh_first = (elm)->field.cqe_next; \
525 else \
526 (elm)->field.cqe_prev->field.cqe_next = (elm)->field.cqe_next; \
527 _Q_INVALIDATE((elm)->field.cqe_prev); \
528 _Q_INVALIDATE((elm)->field.cqe_next); \
529 } while (0)
530
531 #define CIRCLEQ_REPLACE(head, elm, elm2, field) \
532 do { \
533 if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == CIRCLEQ_END(head)) \
534 (head)->cqh_last = (elm2); \
535 else \
536 (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
537 if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == CIRCLEQ_END(head)) \
538 (head)->cqh_first = (elm2); \
539 else \
540 (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
541 _Q_INVALIDATE((elm)->field.cqe_prev); \
542 _Q_INVALIDATE((elm)->field.cqe_next); \
543 } while (0)
544
545 #endif /* !_SYS_QUEUE_H_ */
66 <refentrytitle>{mantitle}</refentrytitle>
77 <manvolnum>{manvolnum}</manvolnum>
88 <refmiscinfo class="source">i3status</refmiscinfo>
9 <refmiscinfo class="version">v2.8</refmiscinfo>
9 <refmiscinfo class="version">v2.9</refmiscinfo>
1010 <refmiscinfo class="manual">i3 Manual</refmiscinfo>
1111 </refmeta>
1212 <refnamediv>
00 '\" t
11 .\" Title: i3status
22 .\" Author: [see the "AUTHORS" section]
3 .\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
4 .\" Date: 01/05/2014
3 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
4 .\" Date: 03/21/2015
55 .\" Manual: i3 Manual
66 .\" Source: i3status v2.8
77 .\" Language: English
88 .\"
9 .TH "I3STATUS" "1" "01/05/2014" "i3status v2\&.8" "i3 Manual"
9 .TH "I3STATUS" "1" "03/21/2015" "i3status v2\&.8" "i3 Manual"
1010 .\" -----------------------------------------------------------------
1111 .\" * Define some portability stuff
1212 .\" -----------------------------------------------------------------
127127 battery 0 {
128128 format = "%status %percentage %remaining %emptytime"
129129 format_down = "No battery"
130 status_chr = "⚇ CHR""
131 status_bat = "⚡ BAT"
132 status_full = "☻ FULL"
130133 path = "/sys/class/power_supply/BAT%d/uevent"
131134 low_threshold = 10
132135 }
187190 .RE
188191 .\}
189192 .sp
190 Likewise, you can use the color_separator directive to specify the color that will be used to paint the separator bar\&. The separator is always output in color, even when colors are disabled by the colors directive\&.
193 Likewise, you can use the color_separator directive to specify the color that will be used to paint the separator bar\&. The separator is always output in color, even when colors are disabled by the colors directive\&. This option has no effect when output_format is set to i3bar or none\&.
191194 .sp
192195 The interval directive specifies the time in seconds for which i3status will sleep before printing the next status line\&.
193196 .sp
215218 .PP
216219 none
217220 .RS 4
218 Does not use any color codes\&. Separates values by the pipe symbol\&. This should be used with i3bar and can be used for custom scripts\&.
221 Does not use any color codes\&. Separates values by the pipe symbol by default\&. This should be used with i3bar and can be used for custom scripts\&.
219222 .RE
220223 .sp
221224 It\(cqs also possible to use the color_good, color_degraded, color_bad directives to define specific colors per module\&. If one of these directives is defined in a module section its value will override the value defined in the general section just for this module\&.
225 .sp
226 If you don\(cqt fancy the vertical separators between modules i3status/i3bar uses by default, you can employ the separator directive to configure how modules are separated\&. You can either disable the default separator altogether setting it to the empty string\&. You might then define separation as part of a module\(cqs format string\&. This is your only option when using the i3bar output format as the separator is drawn by i3bar directly otherwise\&. For the other output formats, the provided non\-empty string will be automatically enclosed with the necessary coloring bits if color support is enabled\&.
227 .sp
228 \fBExample configuration\fR:
229 .sp
230 .if n \{\
231 .RS 4
232 .\}
233 .nf
234 general {
235 output_format = "xmobar"
236 separator = " "
237 }
238
239 order += "load"
240 order += "disk /"
241
242 load {
243 format = "[ load: %1min, %5min, %15min ]"
244 }
245 disk "/" {
246 format = "%avail"
247 }
248 .fi
249 .if n \{\
250 .RE
251 .\}
222252 .SS "IPv6"
223253 .sp
224254 This module gets the IPv6 address used for outgoing connections (that is, the best available public IPv6 address on your computer)\&.
225255 .sp
226256 \fBExample format_up\fR: %ip
227257 .sp
228 \fBExample format_down\fR no IPv6
258 \fBExample format_down\fR: no IPv6
229259 .SS "Disk"
230260 .sp
231261 Gets used, free, available and total amount of bytes on the given mounted filesystem\&.
249279 The custom prefixes (K, M, G, T) represent multiples of powers of 1024\&.
250280 .RE
251281 .sp
282 It is possible to define a low_threshold that causes the disk text to be displayed using color_bad\&. The low_threshold type can be of threshold_type "bytes_free", "bytes_avail", "percentage_free", or "percentage_avail", where the former two can be prepended by a generic prefix (k, m, g, t) having prefix_type\&. So, if you configure low_threshold to 2, threshold_type to "gbytes_avail", and prefix_type to "binary", and the remaining available disk space is below 2 GiB, it will be colored bad\&. If not specified, threshold_type is assumed to be "percentage_avail" and low_threshold to be set to 0, which implies no coloring at all\&.
283 .sp
284 You can define a different format with the option "format_not_mounted" which is used if the path is not a mount point\&. So you can just empty the output for the given path with adding \(Fcformat_not_mounted=""\(Fo to the config section\&.
285 .sp
252286 \fBExample order\fR: disk /mnt/usbstick
253287 .sp
254288 \fBExample format\fR: %free (%avail)/ %total
256290 \fBExample format\fR: %percentage_used used, %percentage_free free, %percentage_avail avail
257291 .sp
258292 \fBExample prefix_type\fR: custom
293 .sp
294 \fBExample low_threshold\fR: 5
295 .sp
296 \fBExample threshold_type\fR: percentage_free
259297 .SS "Run\-watch"
260298 .sp
261299 Expands the given path to a pidfile and checks if the process ID found inside is valid (that is, if the process is running)\&. You can use this to check if a specific application, such as a VPN client or your DHCP client is running\&.
272310 \fBExample format\fR: %title: %status
273311 .SS "Wireless"
274312 .sp
275 Gets the link quality and ESSID of the given wireless network interface\&. You can specify different format strings for the network being connected or not connected\&.
313 Gets the link quality, frequency and ESSID of the given wireless network interface\&. You can specify different format strings for the network being connected or not connected\&.
314 .sp
315 The special interface name _first_ will be replaced by the first wireless network interface found on the system (excluding devices starting with "lo")\&.
276316 .sp
277317 \fBExample order\fR: wireless wlan0
278318 .sp
279 \fBExample format\fR: W: (%quality at %essid, %bitrate) %ip
319 \fBExample format\fR: W: (%quality at %essid, %bitrate / %frequency) %ip
280320 .SS "Ethernet"
281321 .sp
282322 Gets the IP address and (if possible) the link speed of the given ethernet interface\&. Getting the link speed requires the cap_net_admin capability\&. Set it using setcap cap_net_admin=ep $(which i3status)\&.
323 .sp
324 The special interface name _first_ will be replaced by the first non\-wireless network interface found on the system (excluding devices starting with "lo")\&.
283325 .sp
284326 \fBExample order\fR: ethernet eth0
285327 .sp
286328 \fBExample format\fR: E: %ip (%speed)
287329 .SS "Battery"
288330 .sp
289 Gets the status (charging, discharging, running), percentage, remaining time and power consumption (in Watts) of the given battery and when it\(cqs estimated to be empty\&. If you want to use the last full capacity instead of the design capacity (when using the design capacity, it may happen that your battery is at 23% when fully charged because it\(cqs old\&. In general, I want to see it this way, because it tells me how worn off my battery is\&.), just specify last_full_capacity = true\&.
331 Gets the status (charging, discharging, running), percentage, remaining time and power consumption (in Watts) of the given battery and when it\(cqs estimated to be empty\&. If you want to use the last full capacity instead of the design capacity (when using the design capacity, it may happen that your battery is at 23% when fully charged because it\(cqs old\&. In general, I want to see it this way, because it tells me how worn off my battery is\&.), just specify last_full_capacity = true\&. You can hide seconds in the remaining time and empty time estimations by setting hide_seconds = true\&.
290332 .sp
291333 If you want the battery percentage to be shown without decimals, add integer_battery_capacity = true\&.
292334 .sp
294336 .sp
295337 It is possible to define a low_threshold that causes the battery text to be colored red\&. The low_threshold type can be of threshold_type "time" or "percentage"\&. So, if you configure low_threshold to 10 and threshold_type to "time", and your battery lasts another 9 minutes, it will be colored red\&.
296338 .sp
339 Optionally custom strings including any UTF\-8 symbols can be used for different battery states\&. This makes it possible to display individual symbols for each state (charging, discharging, full) Of course it will also work with special iconic fonts, such as FontAwesome\&. If any of this special status strings is omitted, the default (CHR, BAT, FULL) is used\&.
340 .sp
297341 \fBExample order\fR: battery 0
298342 .sp
299343 \fBExample format\fR: %status %remaining (%emptytime %consumption)
344 .sp
345 \fBExample format_down\fR: No battery
346 .sp
347 \fBExample status_chr\fR: ⚇ CHR
348 .sp
349 \fBExample status_bat\fR: ⚡ BAT
350 .sp
351 \fBExample status_full\fR: ☻ FULL
300352 .sp
301353 \fBExample low_threshold\fR: 30
302354 .sp
355407 \fBExample format\fR: %{%a, %b %d%}, %Y%N \- %H
356408 .SS "Volume"
357409 .sp
358 Outputs the volume of the specified mixer on the specified device\&. Works only on Linux because it uses ALSA\&. A simplified configuration can be used on FreeBSD and OpenBSD due to the lack of ALSA, the device and mixer options can be ignored on these systems\&. On these systems the OSS API is used instead to query /dev/mixer directly if mixer_dix is \-1, otherwise /dev/mixer+mixer_idx+\&.
410 Outputs the volume of the specified mixer on the specified device\&. If compiled with USE_PULSEAUDIO, may work on any system with PulseAudio\&. Otherwise only ALSA is available and therefore will only work on Linux\&. In this case a simplified configuration can be used on FreeBSD and OpenBSD due to the lack of ALSA, the device and mixer options can be ignored on these systems\&. On these systems the OSS API is used instead to query /dev/mixer directly if mixer_idx is \-1, otherwise /dev/mixer+mixer_idx+\&.
411 .sp
412 To get PulseAudio volume information, one must use the following format in the device line:
413 .sp
414 .if n \{\
415 .RS 4
416 .\}
417 .nf
418 device = "pulse"
419 .fi
420 .if n \{\
421 .RE
422 .\}
423 .sp
424 or
425 .sp
426 .if n \{\
427 .RS 4
428 .\}
429 .nf
430 device = "pulse:N"
431 .fi
432 .if n \{\
433 .RE
434 .\}
435 .sp
436 where N is the index of the PulseAudio sink\&. If no sink is specified the default is used\&. If the device string is missing or is set to "default", PulseAudio will be tried if detected and will fallback to ALSA (Linux) or OSS (FreeBSD/OpenBSD)\&.
359437 .sp
360438 \fBExample order\fR: volume master
361439 .sp
378456 .if n \{\
379457 .RE
380458 .\}
459 .sp
460 \fBExample configuration (PulseAudio)\fR:
461 .sp
462 .if n \{\
463 .RS 4
464 .\}
465 .nf
466 volume master {
467 format = "♪: %volume"
468 format_muted = "♪: muted (%volume)"
469 device = "pulse:1"
470 }
471 .fi
472 .if n \{\
473 .RE
474 .\}
475 .SH "UNIVERSAL MODULE OPTIONS"
476 .sp
477 When using the i3bar output format, there are a few additional options that can be used with all modules to customize their appearance:
478 .PP
479 align
480 .RS 4
481 The alignment policy to use when the minimum width (see below) is not reached\&. Either
482 center
483 (default),
484 right
485 or
486 left\&.
487 .RE
488 .PP
489 min_width
490 .RS 4
491 The minimum width (in pixels) the module should occupy\&. If the module takes less space than the specified size, the block will be padded to the left and/or the right side, according to the defined alignment policy\&. This is useful when you want to prevent the whole status line from shifting when values take more or less space between each iteration\&. The option can also be a string\&. In this case, the width of the given text determines the minimum width of the block\&. This is useful when you want to set a sensible minimum width regardless of which font you are using, and at what particular size\&. Please note that a number enclosed with quotes will still be treated as a number\&.
492 .RE
493 .sp
494 \fBExample configuration\fR:
495 .sp
496 .if n \{\
497 .RS 4
498 .\}
499 .nf
500 disk "/" {
501 format = "%avail"
502 align = "left"
503 min_width = 100
504 }
505 .fi
506 .if n \{\
507 .RE
508 .\}
381509 .SH "USING I3STATUS WITH DZEN2"
382510 .sp
383511 After installing dzen2, you can directly use it with i3status\&. Just ensure that output_format is set to dzen2\&.
00 i3status(1)
11 ===========
22 Michael Stapelberg <michael@i3wm.org>
3 v2.8, January 2014
3 v2.9, March 2015
44
55 == NAME
66
7373 battery 0 {
7474 format = "%status %percentage %remaining %emptytime"
7575 format_down = "No battery"
76 status_chr = "⚇ CHR""
77 status_bat = "⚡ BAT"
78 status_full = "☻ FULL"
7679 path = "/sys/class/power_supply/BAT%d/uevent"
7780 low_threshold = 10
7881 }
131134
132135 Likewise, you can use the +color_separator+ directive to specify the color that
133136 will be used to paint the separator bar. The separator is always output in
134 color, even when colors are disabled by the +colors+ directive.
137 color, even when colors are disabled by the +colors+ directive. This option has
138 no effect when +output_format+ is set to +i3bar+ or +none+.
135139
136140 The +interval+ directive specifies the time in seconds for which i3status will
137141 sleep before printing the next status line.
159163 should only used for such quick glances, because it will only support very
160164 basic output-features (for example you only get 3 bits of color depth).
161165 none::
162 Does not use any color codes. Separates values by the pipe symbol. This should
163 be used with i3bar and can be used for custom scripts.
166 Does not use any color codes. Separates values by the pipe symbol by default.
167 This should be used with i3bar and can be used for custom scripts.
164168
165169 It's also possible to use the color_good, color_degraded, color_bad directives
166170 to define specific colors per module. If one of these directives is defined
167171 in a module section its value will override the value defined in the general
168172 section just for this module.
169173
174 If you don't fancy the vertical separators between modules i3status/i3bar
175 uses by default, you can employ the +separator+ directive to configure how
176 modules are separated. You can either disable the default separator altogether
177 setting it to the empty string. You might then define separation as part of a
178 module's format string. This is your only option when using the i3bar output
179 format as the separator is drawn by i3bar directly otherwise. For the other
180 output formats, the provided non-empty string will be automatically enclosed
181 with the necessary coloring bits if color support is enabled.
182
183 *Example configuration*:
184 -------------------------------------------------------------
185 general {
186 output_format = "xmobar"
187 separator = " "
188 }
189
190 order += "load"
191 order += "disk /"
192
193 load {
194 format = "[ load: %1min, %5min, %15min ]"
195 }
196 disk "/" {
197 format = "%avail"
198 }
199 -------------------------------------------------------------
200
170201 === IPv6
171202
172203 This module gets the IPv6 address used for outgoing connections (that is, the
174205
175206 *Example format_up*: +%ip+
176207
177 *Example format_down* +no IPv6+
208 *Example format_down*: +no IPv6+
178209
179210 === Disk
180211
195226 custom::
196227 The custom prefixes (K, M, G, T) represent multiples of powers of 1024.
197228
229 It is possible to define a low_threshold that causes the disk text to be
230 displayed using color_bad. The low_threshold type can be of threshold_type
231 "bytes_free", "bytes_avail", "percentage_free", or "percentage_avail", where
232 the former two can be prepended by a generic prefix (k, m, g, t) having
233 prefix_type. So, if you configure low_threshold to 2, threshold_type to
234 "gbytes_avail", and prefix_type to "binary", and the remaining available disk
235 space is below 2 GiB, it will be colored bad. If not specified, threshold_type
236 is assumed to be "percentage_avail" and low_threshold to be set to 0, which
237 implies no coloring at all.
238
239 You can define a different format with the option "format_not_mounted"
240 which is used if the path is not a mount point. So you can just empty
241 the output for the given path with adding »format_not_mounted=""«
242 to the config section.
243
198244 *Example order*: +disk /mnt/usbstick+
199245
200246 *Example format*: +%free (%avail)/ %total+
202248 *Example format*: +%percentage_used used, %percentage_free free, %percentage_avail avail+
203249
204250 *Example prefix_type*: +custom+
251
252 *Example low_threshold*: +5+
253
254 *Example threshold_type*: +percentage_free+
205255
206256 === Run-watch
207257
224274
225275 === Wireless
226276
227 Gets the link quality and ESSID of the given wireless network interface. You
228 can specify different format strings for the network being connected or not
229 connected.
277 Gets the link quality, frequency and ESSID of the given wireless network
278 interface. You can specify different format strings for the network being
279 connected or not connected.
280
281 The special interface name `_first_` will be replaced by the first wireless
282 network interface found on the system (excluding devices starting with "lo").
230283
231284 *Example order*: +wireless wlan0+
232285
233 *Example format*: +W: (%quality at %essid, %bitrate) %ip+
286 *Example format*: +W: (%quality at %essid, %bitrate / %frequency) %ip+
234287
235288 === Ethernet
236289
237290 Gets the IP address and (if possible) the link speed of the given ethernet
238291 interface. Getting the link speed requires the cap_net_admin capability. Set
239292 it using +setcap cap_net_admin=ep $(which i3status)+.
293
294 The special interface name `_first_` will be replaced by the first non-wireless
295 network interface found on the system (excluding devices starting with "lo").
240296
241297 *Example order*: +ethernet eth0+
242298
250306 design capacity (when using the design capacity, it may happen that your
251307 battery is at 23% when fully charged because it’s old. In general, I want to
252308 see it this way, because it tells me how worn off my battery is.), just specify
253 +last_full_capacity = true+.
309 +last_full_capacity = true+. You can hide seconds in the remaining time and
310 empty time estimations by setting +hide_seconds = true+.
254311
255312 If you want the battery percentage to be shown without decimals, add
256313 +integer_battery_capacity = true+.
265322 "percentage". So, if you configure low_threshold to 10 and threshold_type to
266323 "time", and your battery lasts another 9 minutes, it will be colored red.
267324
325 Optionally custom strings including any UTF-8 symbols can be used for different
326 battery states. This makes it possible to display individual symbols
327 for each state (charging, discharging, full)
328 Of course it will also work with special iconic fonts, such as FontAwesome.
329 If any of this special status strings is omitted, the default (CHR, BAT, FULL)
330 is used.
331
268332 *Example order*: +battery 0+
269333
270334 *Example format*: +%status %remaining (%emptytime %consumption)+
335
336 *Example format_down*: +No battery+
337
338 *Example status_chr*: +⚇ CHR+
339
340 *Example status_bat*: +⚡ BAT+
341
342 *Example status_full*: +☻ FULL+
271343
272344 *Example low_threshold*: +30+
273345
370442 device = "default"
371443 mixer = "Master"
372444 mixer_idx = 0
445 }
446 -------------------------------------------------------------
447
448 == Universal module options
449
450 When using the i3bar output format, there are a few additional options that
451 can be used with all modules to customize their appearance:
452
453 align::
454 The alignment policy to use when the minimum width (see below) is not
455 reached. Either +center+ (default), +right+ or +left+.
456 min_width::
457 The minimum width (in pixels) the module should occupy. If the module takes
458 less space than the specified size, the block will be padded to the left
459 and/or the right side, according to the defined alignment policy. This is
460 useful when you want to prevent the whole status line from shifting when
461 values take more or less space between each iteration.
462 The option can also be a string. In this case, the width of the given text
463 determines the minimum width of the block. This is useful when you want to
464 set a sensible minimum width regardless of which font you are using, and at
465 what particular size. Please note that a number enclosed with quotes will
466 still be treated as a number.
467
468 *Example configuration*:
469 -------------------------------------------------------------
470 disk "/" {
471 format = "%avail"
472 align = "left"
473 min_width = 100
373474 }
374475 -------------------------------------------------------------
375476
0 // vim:ts=4:sw=4:expandtab
1 #include <sys/stat.h>
2 #include <stdlib.h>
3 #include <ifaddrs.h>
4
5 #include "i3status.h"
6
7 const char *first_eth_interface(const net_type_t type) {
8 static char *interface = NULL;
9 struct ifaddrs *ifaddr, *addrp;
10 struct stat stbuf;
11 static char path[1024];
12
13 getifaddrs(&ifaddr);
14
15 if (ifaddr == NULL)
16 return NULL;
17
18 free(interface);
19 interface = NULL;
20 for (addrp = ifaddr;
21 addrp != NULL;
22 addrp = addrp->ifa_next) {
23 if (strncasecmp("lo", addrp->ifa_name, strlen("lo")) == 0)
24 continue;
25 // Skip this interface if it is a wireless interface.
26 snprintf(path, sizeof(path), "/sys/class/net/%s/wireless", addrp->ifa_name);
27 const bool is_wireless = (stat(path, &stbuf) == 0);
28 if ((is_wireless && type == NET_TYPE_ETHERNET) ||
29 (!is_wireless && type == NET_TYPE_WIRELESS))
30 continue;
31 interface = strdup(addrp->ifa_name);
32 break;
33 }
34
35 freeifaddrs(ifaddr);
36 return interface;
37 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <sys/types.h>
22 #include <string.h>
33 #include <stdarg.h>
1414 *
1515 */
1616 bool slurp(const char *filename, char *destination, int size) {
17 int fd;
17 int fd;
1818
19 if ((fd = open(filename, O_RDONLY)) == -1)
20 return false;
19 if ((fd = open(filename, O_RDONLY)) == -1)
20 return false;
2121
22 /* We need one byte for the trailing 0 byte */
23 int n = read(fd, destination, size-1);
24 if (n != -1)
25 destination[n] = '\0';
26 (void)close(fd);
22 /* We need one byte for the trailing 0 byte */
23 int n = read(fd, destination, size - 1);
24 if (n != -1)
25 destination[n] = '\0';
26 (void)close(fd);
2727
28 return true;
28 return true;
2929 }
3030
3131 /*
3434 *
3535 */
3636 char *skip_character(char *input, char character, int amount) {
37 char *walk;
38 size_t len = strlen(input);
39 int blanks = 0;
37 char *walk;
38 size_t len = strlen(input);
39 int blanks = 0;
4040
41 for (walk = input; ((size_t)(walk - input) < len) && (blanks < amount); walk++)
42 if (*walk == character)
43 blanks++;
41 for (walk = input; ((size_t)(walk - input) < len) && (blanks < amount); walk++)
42 if (*walk == character)
43 blanks++;
4444
45 return (walk == input ? walk : walk-1);
45 return (walk == input ? walk : walk - 1);
4646 }
4747
4848 /*
5050 *
5151 */
5252 void die(const char *fmt, ...) {
53 char buffer[512];
54 va_list ap;
55 va_start(ap, fmt);
56 (void)vsnprintf(buffer, sizeof(buffer), fmt, ap);
57 va_end(ap);
53 char buffer[512];
54 va_list ap;
55 va_start(ap, fmt);
56 (void)vsnprintf(buffer, sizeof(buffer), fmt, ap);
57 va_end(ap);
5858
59 fprintf(stderr, "%s", buffer);
60 exit(EXIT_FAILURE);
59 fprintf(stderr, "%s", buffer);
60 exit(EXIT_FAILURE);
6161 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <stdbool.h>
22 #include <string.h>
33 #include <stdio.h>
1414 *
1515 */
1616 char *color(const char *colorstr) {
17 static char colorbuf[32];
18 if (!cfg_getbool(cfg_general, "colors")) {
19 colorbuf[0] = '\0';
20 return colorbuf;
21 }
22 if (output_format == O_DZEN2)
23 (void)snprintf(colorbuf, sizeof(colorbuf), "^fg(%s)", cfg_getstr(cfg_general, colorstr));
24 else if (output_format == O_XMOBAR)
25 (void)snprintf(colorbuf, sizeof(colorbuf), "<fc=%s>", cfg_getstr(cfg_general, colorstr));
26 else if (output_format == O_TERM) {
27 /* The escape-sequence for color is <CSI><col>;1m (bright/bold
28 * output), where col is a 3-bit rgb-value with b in the
29 * least-significant bit. We round the given color to the
30 * nearist 3-bit-depth color and output the escape-sequence */
31 char *str = cfg_getstr(cfg_general, colorstr);
32 int col = strtol(str + 1, NULL, 16);
33 int r = (col & (0xFF << 0)) / 0x80;
34 int g = (col & (0xFF << 8)) / 0x8000;
35 int b = (col & (0xFF << 16)) / 0x800000;
36 col = (r << 2) | (g << 1) | b;
37 (void)snprintf(colorbuf, sizeof(colorbuf), "\033[3%d;1m", col);
38 }
17 static char colorbuf[32];
18 if (!cfg_getbool(cfg_general, "colors")) {
19 colorbuf[0] = '\0';
3920 return colorbuf;
21 }
22 if (output_format == O_DZEN2)
23 (void)snprintf(colorbuf, sizeof(colorbuf), "^fg(%s)", cfg_getstr(cfg_general, colorstr));
24 else if (output_format == O_XMOBAR)
25 (void)snprintf(colorbuf, sizeof(colorbuf), "<fc=%s>", cfg_getstr(cfg_general, colorstr));
26 else if (output_format == O_TERM) {
27 /* The escape-sequence for color is <CSI><col>;1m (bright/bold
28 * output), where col is a 3-bit rgb-value with b in the
29 * least-significant bit. We round the given color to the
30 * nearist 3-bit-depth color and output the escape-sequence */
31 char *str = cfg_getstr(cfg_general, colorstr);
32 int col = strtol(str + 1, NULL, 16);
33 int r = (col & (0xFF << 0)) / 0x80;
34 int g = (col & (0xFF << 8)) / 0x8000;
35 int b = (col & (0xFF << 16)) / 0x800000;
36 col = (r << 2) | (g << 1) | b;
37 (void)snprintf(colorbuf, sizeof(colorbuf), "\033[3%d;1m", col);
38 }
39 return colorbuf;
4040 }
4141
4242 /*
4444 *
4545 */
4646 char *endcolor(void) {
47 if (output_format == O_XMOBAR)
48 return "</fc>";
49 else if (output_format == O_TERM)
50 return "\033[0m";
51 else return "";
47 if (output_format == O_XMOBAR)
48 return "</fc>";
49 else if (output_format == O_TERM)
50 return "\033[0m";
51 else
52 return "";
5253 }
5354
54 void print_seperator(void) {
55 if (output_format == O_DZEN2)
56 printf("^fg(%s)^p(5;-2)^ro(2)^p()^fg()^p(5)", cfg_getstr(cfg_general, "color_separator"));
57 else if (output_format == O_XMOBAR)
58 printf("<fc=%s> | </fc>", cfg_getstr(cfg_general, "color_separator"));
59 else if (output_format == O_TERM)
60 printf(" %s|%s ", color("color_separator"), endcolor());
61 else if (output_format == O_NONE)
62 printf(" | ");
55 void print_separator(const char *separator) {
56 if (output_format == O_I3BAR || strlen(separator) == 0)
57 return;
58
59 if (output_format == O_DZEN2)
60 printf("^fg(%s)%s^fg()", cfg_getstr(cfg_general, "color_separator"), separator);
61 else if (output_format == O_XMOBAR)
62 printf("<fc=%s>%s</fc>", cfg_getstr(cfg_general, "color_separator"), separator);
63 else if (output_format == O_TERM)
64 printf("%s%s%s", color("color_separator"), separator, endcolor());
65 else if (output_format == O_NONE)
66 printf("%s", separator);
6367 }
6468
6569 /*
6670 * The term-output hides the cursor. We call this on exit to reset that.
6771 */
6872 void reset_cursor(void) {
69 printf("\033[?25h");
73 printf("\033[?25h");
7074 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <ctype.h>
22 #include <time.h>
33 #include <string.h>
2020 #include <machine/apmvar.h>
2121 #endif
2222
23 #define BATT_STATUS_NAME(status) \
24 (status == CS_CHARGING ? "CHR" : \
25 (status == CS_DISCHARGING ? "BAT" : "FULL"))
23 #if defined(__NetBSD__)
24 #include <fcntl.h>
25 #include <prop/proplib.h>
26 #include <sys/envsys.h>
27 #endif
28
2629 /*
2730 * Get battery information from /sys. Note that it uses the design capacity to
2831 * calculate the percentage, not the last full capacity, so you can see how
2932 * worn off your battery is.
3033 *
3134 */
32 void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity) {
33 time_t empty_time;
34 struct tm *empty_tm;
35 char buf[1024];
36 char statusbuf[16];
37 char percentagebuf[16];
38 char remainingbuf[256];
39 char emptytimebuf[256];
40 char consumptionbuf[256];
41 const char *walk, *last;
42 char *outwalk = buffer;
43 bool watt_as_unit;
44 bool colorful_output = false;
45 int full_design = -1,
46 remaining = -1,
47 present_rate = -1,
48 voltage = -1;
49 charging_status_t status = CS_DISCHARGING;
50
51 memset(statusbuf, '\0', sizeof(statusbuf));
52 memset(percentagebuf, '\0', sizeof(percentagebuf));
53 memset(remainingbuf, '\0', sizeof(remainingbuf));
54 memset(emptytimebuf, '\0', sizeof(emptytimebuf));
55 memset(consumptionbuf, '\0', sizeof(consumptionbuf));
56
57 static char batpath[512];
58 sprintf(batpath, path, number);
59 INSTANCE(batpath);
35 void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, const char *status_chr, const char *status_bat, const char *status_full, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity, bool hide_seconds) {
36 time_t empty_time;
37 struct tm *empty_tm;
38 char buf[1024];
39 char statusbuf[16];
40 char percentagebuf[16];
41 char remainingbuf[256];
42 char emptytimebuf[256];
43 char consumptionbuf[256];
44 const char *walk, *last;
45 char *outwalk = buffer;
46 bool watt_as_unit = false;
47 bool colorful_output = false;
48 int full_design = -1,
49 remaining = -1,
50 present_rate = -1,
51 voltage = -1;
52 charging_status_t status = CS_DISCHARGING;
53
54 memset(statusbuf, '\0', sizeof(statusbuf));
55 memset(percentagebuf, '\0', sizeof(percentagebuf));
56 memset(remainingbuf, '\0', sizeof(remainingbuf));
57 memset(emptytimebuf, '\0', sizeof(emptytimebuf));
58 memset(consumptionbuf, '\0', sizeof(consumptionbuf));
59
60 static char batpath[512];
61 sprintf(batpath, path, number);
62 INSTANCE(batpath);
63
64 #define BATT_STATUS_NAME(status) \
65 (status == CS_CHARGING ? status_chr : (status == CS_DISCHARGING ? status_bat : status_full))
6066
6167 #if defined(LINUX)
62 if (!slurp(batpath, buf, sizeof(buf))) {
63 OUTPUT_FULL_TEXT(format_down);
64 return;
65 }
66
67 for (walk = buf, last = buf; (walk-buf) < 1024; walk++) {
68 if (*walk == '\n') {
69 last = walk+1;
70 continue;
71 }
72
73 if (*walk != '=')
74 continue;
75
76 if (BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_NOW")) {
77 watt_as_unit = true;
78 remaining = atoi(walk+1);
79 }
80 else if (BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_NOW")) {
81 watt_as_unit = false;
82 remaining = atoi(walk+1);
83 }
84 else if (BEGINS_WITH(last, "POWER_SUPPLY_CURRENT_NOW"))
85 present_rate = atoi(walk+1);
86 else if (BEGINS_WITH(last, "POWER_SUPPLY_VOLTAGE_NOW"))
87 voltage = atoi(walk+1);
88 /* on some systems POWER_SUPPLY_POWER_NOW does not exist, but actually
89 * it is the same as POWER_SUPPLY_CURRENT_NOW but with μWh as
90 * unit instead of μAh. We will calculate it as we need it
91 * later. */
92 else if (BEGINS_WITH(last, "POWER_SUPPLY_POWER_NOW"))
93 present_rate = atoi(walk+1);
94 else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Charging"))
95 status = CS_CHARGING;
96 else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Full"))
97 status = CS_FULL;
98 else {
99 /* The only thing left is the full capacity */
100 if (last_full_capacity) {
101 if (!BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL") &&
102 !BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL"))
103 continue;
104 } else {
105 if (!BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL_DESIGN") &&
106 !BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL_DESIGN"))
107 continue;
108 }
109
110 full_design = atoi(walk+1);
111 }
112 }
113
114 /* the difference between POWER_SUPPLY_ENERGY_NOW and
115 * POWER_SUPPLY_CHARGE_NOW is the unit of measurement. The energy is
116 * given in mWh, the charge in mAh. So calculate every value given in
117 * ampere to watt */
118 if (!watt_as_unit) {
119 present_rate = (((float)voltage / 1000.0) * ((float)present_rate / 1000.0));
68 if (!slurp(batpath, buf, sizeof(buf))) {
69 OUTPUT_FULL_TEXT(format_down);
70 return;
71 }
72
73 for (walk = buf, last = buf; (walk - buf) < 1024; walk++) {
74 if (*walk == '\n') {
75 last = walk + 1;
76 continue;
77 }
78
79 if (*walk != '=')
80 continue;
81
82 if (BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_NOW")) {
83 watt_as_unit = true;
84 remaining = atoi(walk + 1);
85 } else if (BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_NOW")) {
86 watt_as_unit = false;
87 remaining = atoi(walk + 1);
88 } else if (BEGINS_WITH(last, "POWER_SUPPLY_CURRENT_NOW"))
89 present_rate = abs(atoi(walk + 1));
90 else if (BEGINS_WITH(last, "POWER_SUPPLY_VOLTAGE_NOW"))
91 voltage = abs(atoi(walk + 1));
92 /* on some systems POWER_SUPPLY_POWER_NOW does not exist, but actually
93 * it is the same as POWER_SUPPLY_CURRENT_NOW but with μWh as
94 * unit instead of μAh. We will calculate it as we need it
95 * later. */
96 else if (BEGINS_WITH(last, "POWER_SUPPLY_POWER_NOW"))
97 present_rate = abs(atoi(walk + 1));
98 else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Charging"))
99 status = CS_CHARGING;
100 else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Full"))
101 status = CS_FULL;
102 else {
103 /* The only thing left is the full capacity */
104 if (last_full_capacity) {
105 if (!BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL") &&
106 !BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL"))
107 continue;
108 } else {
109 if (!BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL_DESIGN") &&
110 !BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL_DESIGN"))
111 continue;
112 }
113
114 full_design = atoi(walk + 1);
115 }
116 }
117
118 /* the difference between POWER_SUPPLY_ENERGY_NOW and
119 * POWER_SUPPLY_CHARGE_NOW is the unit of measurement. The energy is
120 * given in mWh, the charge in mAh. So calculate every value given in
121 * ampere to watt */
122 if (!watt_as_unit) {
123 present_rate = (((float)voltage / 1000.0) * ((float)present_rate / 1000.0));
124
125 if (voltage != -1) {
120126 remaining = (((float)voltage / 1000.0) * ((float)remaining / 1000.0));
121127 full_design = (((float)voltage / 1000.0) * ((float)full_design / 1000.0));
122128 }
123
124 if ((full_design == -1) || (remaining == -1)) {
125 OUTPUT_FULL_TEXT(format_down);
126 return;
127 }
128
129 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
130
131 float percentage_remaining = (((float)remaining / (float)full_design) * 100);
132 if (integer_battery_capacity) {
133 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%.00f%%", percentage_remaining);
134 } else {
135 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%.02f%%", percentage_remaining);
136 }
137
138 if (present_rate > 0) {
139 float remaining_time;
140 int seconds, hours, minutes, seconds_remaining;
141 if (status == CS_CHARGING)
142 remaining_time = ((float)full_design - (float)remaining) / (float)present_rate;
143 else if (status == CS_DISCHARGING)
144 remaining_time = ((float)remaining / (float)present_rate);
145 else remaining_time = 0;
146
147 seconds_remaining = (int)(remaining_time * 3600.0);
148
149 hours = seconds_remaining / 3600;
150 seconds = seconds_remaining - (hours * 3600);
151 minutes = seconds / 60;
152 seconds -= (minutes * 60);
153
154 if (status == CS_DISCHARGING && low_threshold > 0) {
155 if (strncmp(threshold_type, "percentage", strlen(threshold_type)) == 0
156 && percentage_remaining < low_threshold) {
157 START_COLOR("color_bad");
158 colorful_output = true;
159 } else if (strncmp(threshold_type, "time", strlen(threshold_type)) == 0
160 && seconds_remaining < 60 * low_threshold) {
161 START_COLOR("color_bad");
162 colorful_output = true;
163 } else {
164 colorful_output = false;
165 }
166 }
167
168 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02d:%02d:%02d",
169 max(hours, 0), max(minutes, 0), max(seconds, 0));
170
171 empty_time = time(NULL);
172 empty_time += seconds_remaining;
173 empty_tm = localtime(&empty_time);
174
175 (void)snprintf(emptytimebuf, sizeof(emptytimebuf), "%02d:%02d:%02d",
176 max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0), max(empty_tm->tm_sec, 0));
177
178 (void)snprintf(consumptionbuf, sizeof(consumptionbuf), "%1.2fW",
179 ((float)present_rate / 1000.0 / 1000.0));
180 } else {
181 /* On some systems, present_rate may not exist. Still, make sure
182 * we colorize the output if threshold_type is set to percentage
183 * (since we don't have any information on remaining time). */
184 if (status == CS_DISCHARGING && low_threshold > 0) {
185 if (strncmp(threshold_type, "percentage", strlen(threshold_type)) == 0
186 && percentage_remaining < low_threshold) {
187 START_COLOR("color_bad");
188 colorful_output = true;
189 }
190 }
191 }
129 }
130
131 if ((full_design == -1) || (remaining == -1)) {
132 OUTPUT_FULL_TEXT(format_down);
133 return;
134 }
135
136 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
137
138 float percentage_remaining = (((float)remaining / (float)full_design) * 100);
139 if (integer_battery_capacity) {
140 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%.00f%%", percentage_remaining);
141 } else {
142 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%.02f%%", percentage_remaining);
143 }
144
145 if (present_rate > 0) {
146 float remaining_time;
147 int seconds, hours, minutes, seconds_remaining;
148 if (status == CS_CHARGING)
149 remaining_time = ((float)full_design - (float)remaining) / (float)present_rate;
150 else if (status == CS_DISCHARGING)
151 remaining_time = ((float)remaining / (float)present_rate);
152 else
153 remaining_time = 0;
154
155 seconds_remaining = (int)(remaining_time * 3600.0);
156
157 hours = seconds_remaining / 3600;
158 seconds = seconds_remaining - (hours * 3600);
159 minutes = seconds / 60;
160 seconds -= (minutes * 60);
161
162 if (status == CS_DISCHARGING && low_threshold > 0) {
163 if (strcasecmp(threshold_type, "percentage") == 0 && percentage_remaining < low_threshold) {
164 START_COLOR("color_bad");
165 colorful_output = true;
166 } else if (strcasecmp(threshold_type, "time") == 0 && seconds_remaining < 60 * low_threshold) {
167 START_COLOR("color_bad");
168 colorful_output = true;
169 } else {
170 colorful_output = false;
171 }
172 }
173
174 if (hide_seconds)
175 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02d:%02d",
176 max(hours, 0), max(minutes, 0));
177 else
178 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02d:%02d:%02d",
179 max(hours, 0), max(minutes, 0), max(seconds, 0));
180
181 empty_time = time(NULL);
182 empty_time += seconds_remaining;
183 empty_tm = localtime(&empty_time);
184
185 if (hide_seconds)
186 (void)snprintf(emptytimebuf, sizeof(emptytimebuf), "%02d:%02d",
187 max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0));
188 else
189 (void)snprintf(emptytimebuf, sizeof(emptytimebuf), "%02d:%02d:%02d",
190 max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0), max(empty_tm->tm_sec, 0));
191
192 (void)snprintf(consumptionbuf, sizeof(consumptionbuf), "%1.2fW",
193 ((float)present_rate / 1000.0 / 1000.0));
194 } else {
195 /* On some systems, present_rate may not exist. Still, make sure
196 * we colorize the output if threshold_type is set to percentage
197 * (since we don't have any information on remaining time). */
198 if (status == CS_DISCHARGING && low_threshold > 0) {
199 if (strcasecmp(threshold_type, "percentage") == 0 && percentage_remaining < low_threshold) {
200 START_COLOR("color_bad");
201 colorful_output = true;
202 }
203 }
204 }
192205 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
193 int state;
194 int sysctl_rslt;
195 size_t sysctl_size = sizeof(sysctl_rslt);
196
197 if (sysctlbyname(BATT_LIFE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
198 OUTPUT_FULL_TEXT(format_down);
199 return;
200 }
201
202 present_rate = sysctl_rslt;
203 if (sysctlbyname(BATT_TIME, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
204 OUTPUT_FULL_TEXT(format_down);
205 return;
206 }
207
208 remaining = sysctl_rslt;
209 if (sysctlbyname(BATT_STATE, &sysctl_rslt, &sysctl_size, NULL,0) != 0) {
210 OUTPUT_FULL_TEXT(format_down);
211 return;
212 }
213
214 state = sysctl_rslt;
215 if (state == 0 && present_rate == 100)
216 status = CS_FULL;
217 else if (state == 0 && present_rate < 100)
218 status = CS_CHARGING;
219 else
220 status = CS_DISCHARGING;
221
222 full_design = sysctl_rslt;
223
224 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
225
226 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%02d%%",
227 present_rate);
228
229 if (state == 1) {
230 int hours, minutes;
231 minutes = remaining;
232 hours = minutes / 60;
233 minutes -= (hours * 60);
234 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02dh%02d",
235 max(hours, 0), max(minutes, 0));
236 if (strncmp(threshold_type, "percentage", strlen(threshold_type)) == 0
237 && present_rate < low_threshold) {
238 START_COLOR("color_bad");
239 colorful_output = true;
240 } else if (strncmp(threshold_type, "time", strlen(threshold_type)) == 0
241 && remaining < (u_int) low_threshold) {
242 START_COLOR("color_bad");
243 colorful_output = true;
244 }
245 }
206 int state;
207 int sysctl_rslt;
208 size_t sysctl_size = sizeof(sysctl_rslt);
209
210 if (sysctlbyname(BATT_LIFE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
211 OUTPUT_FULL_TEXT(format_down);
212 return;
213 }
214
215 present_rate = sysctl_rslt;
216 if (sysctlbyname(BATT_TIME, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
217 OUTPUT_FULL_TEXT(format_down);
218 return;
219 }
220
221 remaining = sysctl_rslt;
222 if (sysctlbyname(BATT_STATE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
223 OUTPUT_FULL_TEXT(format_down);
224 return;
225 }
226
227 state = sysctl_rslt;
228 if (state == 0 && present_rate == 100)
229 status = CS_FULL;
230 else if (state == 0 && present_rate < 100)
231 status = CS_CHARGING;
232 else
233 status = CS_DISCHARGING;
234
235 full_design = sysctl_rslt;
236
237 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
238
239 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%02d%%",
240 present_rate);
241
242 if (state == 1) {
243 int hours, minutes;
244 minutes = remaining;
245 hours = minutes / 60;
246 minutes -= (hours * 60);
247 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02dh%02d",
248 max(hours, 0), max(minutes, 0));
249 if (strcasecmp(threshold_type, "percentage") == 0 && present_rate < low_threshold) {
250 START_COLOR("color_bad");
251 colorful_output = true;
252 } else if (strcasecmp(threshold_type, "time") == 0 && remaining < (u_int)low_threshold) {
253 START_COLOR("color_bad");
254 colorful_output = true;
255 }
256 }
246257 #elif defined(__OpenBSD__)
247 /*
258 /*
248259 * We're using apm(4) here, which is the interface to acpi(4) on amd64/i386 and
249260 * the generic interface on macppc/sparc64/zaurus, instead of using sysctl(3) and
250261 * probing acpi(4) devices.
251262 */
252 struct apm_power_info apm_info;
253 int apm_fd;
254
255 apm_fd = open("/dev/apm", O_RDONLY);
256 if (apm_fd < 0) {
257 OUTPUT_FULL_TEXT("can't open /dev/apm");
258 return;
259 }
260 if (ioctl(apm_fd, APM_IOC_GETPOWER, &apm_info) < 0)
261 OUTPUT_FULL_TEXT("can't read power info");
262
263 close(apm_fd);
264
265 /* Don't bother to go further if there's no battery present. */
266 if ((apm_info.battery_state == APM_BATTERY_ABSENT) ||
267 (apm_info.battery_state == APM_BATT_UNKNOWN)) {
268 OUTPUT_FULL_TEXT(format_down);
269 return;
270 }
271
272 switch(apm_info.ac_state) {
273 case APM_AC_OFF:
274 status = CS_DISCHARGING;
275 break;
276 case APM_AC_ON:
277 status = CS_CHARGING;
278 break;
279 default:
280 /* If we don't know what's going on, just assume we're discharging. */
281 status = CS_DISCHARGING;
282 break;
283 }
284
285 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
286 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%02d%%", apm_info.battery_life);
287
288 if (status == CS_DISCHARGING && low_threshold > 0) {
289 if (strncmp(threshold_type, "percentage", strlen(threshold_type)) == 0
290 && apm_info.battery_life < low_threshold) {
291 START_COLOR("color_bad");
292 colorful_output = true;
293 } else if (strncmp(threshold_type, "time", strlen(threshold_type)) == 0
294 && apm_info.minutes_left < (u_int) low_threshold) {
295 START_COLOR("color_bad");
296 colorful_output = true;
297 }
298 }
299
300 /* Can't give a meaningful value for remaining minutes if we're charging. */
301 if (status != CS_CHARGING) {
302 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%d", apm_info.minutes_left);
303 } else {
304 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%s", "(CHR)");
305 }
306
307 if (colorful_output)
308 END_COLOR;
263 struct apm_power_info apm_info;
264 int apm_fd;
265
266 apm_fd = open("/dev/apm", O_RDONLY);
267 if (apm_fd < 0) {
268 OUTPUT_FULL_TEXT("can't open /dev/apm");
269 return;
270 }
271 if (ioctl(apm_fd, APM_IOC_GETPOWER, &apm_info) < 0)
272 OUTPUT_FULL_TEXT("can't read power info");
273
274 close(apm_fd);
275
276 /* Don't bother to go further if there's no battery present. */
277 if ((apm_info.battery_state == APM_BATTERY_ABSENT) ||
278 (apm_info.battery_state == APM_BATT_UNKNOWN)) {
279 OUTPUT_FULL_TEXT(format_down);
280 return;
281 }
282
283 switch (apm_info.ac_state) {
284 case APM_AC_OFF:
285 status = CS_DISCHARGING;
286 break;
287 case APM_AC_ON:
288 status = CS_CHARGING;
289 break;
290 default:
291 /* If we don't know what's going on, just assume we're discharging. */
292 status = CS_DISCHARGING;
293 break;
294 }
295
296 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
297 /* integer_battery_capacity is implied as battery_life is already in whole numbers. */
298 (void)snprintf(percentagebuf, sizeof(percentagebuf), "%.00d%%", apm_info.battery_life);
299
300 if (status == CS_DISCHARGING && low_threshold > 0) {
301 if (strcasecmp(threshold_type, "percentage") == 0 && apm_info.battery_life < low_threshold) {
302 START_COLOR("color_bad");
303 colorful_output = true;
304 } else if (strcasecmp(threshold_type, "time") == 0 && apm_info.minutes_left < (u_int)low_threshold) {
305 START_COLOR("color_bad");
306 colorful_output = true;
307 }
308 }
309
310 /* Can't give a meaningful value for remaining minutes if we're charging. */
311 if (status != CS_CHARGING) {
312 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%d", apm_info.minutes_left);
313 } else {
314 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%s", "(CHR)");
315 }
316
317 if (colorful_output)
318 END_COLOR;
319 #elif defined(__NetBSD__)
320 /*
321 * Using envsys(4) via sysmon(4).
322 */
323 int fd, rval, last_full_cap;
324 bool is_found = false;
325 char *sensor_desc;
326 bool is_full = false;
327
328 prop_dictionary_t dict;
329 prop_array_t array;
330 prop_object_iterator_t iter;
331 prop_object_iterator_t iter2;
332 prop_object_t obj, obj2, obj3, obj4, obj5;
333
334 asprintf(&sensor_desc, "acpibat%d", number);
335
336 fd = open("/dev/sysmon", O_RDONLY);
337 if (fd < 0) {
338 OUTPUT_FULL_TEXT("can't open /dev/sysmon");
339 return;
340 }
341
342 rval = prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict);
343 if (rval == -1) {
344 close(fd);
345 return;
346 }
347
348 if (prop_dictionary_count(dict) == 0) {
349 prop_object_release(dict);
350 close(fd);
351 return;
352 }
353
354 iter = prop_dictionary_iterator(dict);
355 if (iter == NULL) {
356 prop_object_release(dict);
357 close(fd);
358 }
359
360 /* iterate over the dictionary returned by the kernel */
361 while ((obj = prop_object_iterator_next(iter)) != NULL) {
362 /* skip this dict if it's not what we're looking for */
363 if ((strlen(prop_dictionary_keysym_cstring_nocopy(obj)) == strlen(sensor_desc)) &&
364 (strncmp(sensor_desc,
365 prop_dictionary_keysym_cstring_nocopy(obj),
366 strlen(sensor_desc)) != 0))
367 continue;
368
369 is_found = true;
370
371 array = prop_dictionary_get_keysym(dict, obj);
372 if (prop_object_type(array) != PROP_TYPE_ARRAY) {
373 prop_object_iterator_release(iter);
374 prop_object_release(dict);
375 close(fd);
376 return;
377 }
378
379 iter2 = prop_array_iterator(array);
380 if (!iter2) {
381 prop_object_iterator_release(iter);
382 prop_object_release(dict);
383 close(fd);
384 return;
385 }
386
387 /* iterate over array of dicts specific to target battery */
388 while ((obj2 = prop_object_iterator_next(iter2)) != NULL) {
389 obj3 = prop_dictionary_get(obj2, "description");
390
391 if (obj3 &&
392 strlen(prop_string_cstring_nocopy(obj3)) == 8 &&
393 strncmp("charging",
394 prop_string_cstring_nocopy(obj3),
395 8) == 0) {
396 obj3 = prop_dictionary_get(obj2, "cur-value");
397
398 if (prop_number_integer_value(obj3))
399 status = CS_CHARGING;
400 else
401 status = CS_DISCHARGING;
402
403 continue;
404 }
405
406 if (obj3 &&
407 strlen(prop_string_cstring_nocopy(obj3)) == 6 &&
408 strncmp("charge",
409 prop_string_cstring_nocopy(obj3),
410 6) == 0) {
411 obj3 = prop_dictionary_get(obj2, "cur-value");
412 obj4 = prop_dictionary_get(obj2, "max-value");
413 obj5 = prop_dictionary_get(obj2, "type");
414
415 remaining = prop_number_integer_value(obj3);
416 full_design = prop_number_integer_value(obj4);
417
418 if (remaining == full_design)
419 is_full = true;
420
421 if (strncmp("Ampere hour",
422 prop_string_cstring_nocopy(obj5),
423 11) == 0)
424 watt_as_unit = false;
425 else
426 watt_as_unit = true;
427
428 continue;
429 }
430
431 if (obj3 &&
432 strlen(prop_string_cstring_nocopy(obj3)) == 14 &&
433 strncmp("discharge rate",
434 prop_string_cstring_nocopy(obj3),
435 14) == 0) {
436 obj3 = prop_dictionary_get(obj2, "cur-value");
437 present_rate = prop_number_integer_value(obj3);
438 continue;
439 }
440
441 if (obj3 &&
442 strlen(prop_string_cstring_nocopy(obj3)) == 13 &&
443 strncmp("last full cap",
444 prop_string_cstring_nocopy(obj3),
445 13) == 0) {
446 obj3 = prop_dictionary_get(obj2, "cur-value");
447 last_full_cap = prop_number_integer_value(obj3);
448 continue;
449 }
450
451 if (obj3 &&
452 strlen(prop_string_cstring_nocopy(obj3)) == 7 &&
453 strncmp("voltage",
454 prop_string_cstring_nocopy(obj3),
455 7) == 0) {
456 obj3 = prop_dictionary_get(obj2, "cur-value");
457 voltage = prop_number_integer_value(obj3);
458 continue;
459 }
460 }
461 prop_object_iterator_release(iter2);
462 }
463
464 prop_object_iterator_release(iter);
465 prop_object_release(dict);
466 close(fd);
467
468 if (!is_found) {
469 OUTPUT_FULL_TEXT(format_down);
470 return;
471 }
472
473 if (last_full_capacity)
474 full_design = last_full_cap;
475
476 if (!watt_as_unit) {
477 present_rate = (((float)voltage / 1000.0) * ((float)present_rate / 1000.0));
478 remaining = (((float)voltage / 1000.0) * ((float)remaining / 1000.0));
479 full_design = (((float)voltage / 1000.0) * ((float)full_design / 1000.0));
480 }
481
482 float percentage_remaining =
483 (((float)remaining / (float)full_design) * 100);
484
485 if (integer_battery_capacity)
486 (void)snprintf(percentagebuf,
487 sizeof(percentagebuf),
488 "%d%%",
489 (int)percentage_remaining);
490 else
491 (void)snprintf(percentagebuf,
492 sizeof(percentagebuf),
493 "%.02f%%",
494 percentage_remaining);
495
496 /*
497 * Handle percentage low_threshold here, and time low_threshold when
498 * we have it.
499 */
500 if (status == CS_DISCHARGING && low_threshold > 0) {
501 if (strcasecmp(threshold_type, "percentage") == 0 && (((float)remaining / (float)full_design) * 100) < low_threshold) {
502 START_COLOR("color_bad");
503 colorful_output = true;
504 }
505 }
506
507 if (is_full)
508 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(CS_FULL));
509 else
510 (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
511
512 /*
513 * The envsys(4) ACPI routines do not appear to provide a 'time
514 * remaining' figure, so we must deduce it.
515 */
516 float remaining_time;
517 int seconds, hours, minutes, seconds_remaining;
518
519 if (status == CS_CHARGING)
520 remaining_time = ((float)full_design - (float)remaining) / (float)present_rate;
521 else if (status == CS_DISCHARGING)
522 remaining_time = ((float)remaining / (float)present_rate);
523 else
524 remaining_time = 0;
525
526 seconds_remaining = (int)(remaining_time * 3600.0);
527
528 hours = seconds_remaining / 3600;
529 seconds = seconds_remaining - (hours * 3600);
530 minutes = seconds / 60;
531 seconds -= (minutes * 60);
532
533 if (status != CS_CHARGING) {
534 if (hide_seconds)
535 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02d:%02d",
536 max(hours, 0), max(minutes, 0));
537 else
538 (void)snprintf(remainingbuf, sizeof(remainingbuf), "%02d:%02d:%02d",
539 max(hours, 0), max(minutes, 0), max(seconds, 0));
540
541 if (low_threshold > 0) {
542 if (strcasecmp(threshold_type, "time") == 0 && ((float)seconds_remaining / 60.0) < (u_int)low_threshold) {
543 START_COLOR("color_bad");
544 colorful_output = true;
545 }
546 }
547 } else {
548 if (hide_seconds)
549 (void)snprintf(remainingbuf, sizeof(remainingbuf), "(%02d:%02d until full)",
550 max(hours, 0), max(minutes, 0));
551 else
552 (void)snprintf(remainingbuf, sizeof(remainingbuf), "(%02d:%02d:%02d until full)",
553 max(hours, 0), max(minutes, 0), max(seconds, 0));
554 }
555
556 empty_time = time(NULL);
557 empty_time += seconds_remaining;
558 empty_tm = localtime(&empty_time);
559
560 /* No need to show empty time if battery is charging */
561 if (status != CS_CHARGING) {
562 if (hide_seconds)
563 (void)snprintf(emptytimebuf, sizeof(emptytimebuf), "%02d:%02d",
564 max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0));
565 else
566 (void)snprintf(emptytimebuf, sizeof(emptytimebuf), "%02d:%02d:%02d",
567 max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0), max(empty_tm->tm_sec, 0));
568 }
569
570 (void)snprintf(consumptionbuf, sizeof(consumptionbuf), "%1.2fW",
571 ((float)present_rate / 1000.0 / 1000.0));
309572 #endif
310573
311 #define EAT_SPACE_FROM_OUTPUT_IF_EMPTY(_buf) \
312 do { \
313 if (strlen(_buf) == 0) { \
314 if (outwalk > buffer && isspace(outwalk[-1])) \
315 outwalk--; \
316 else if (isspace(*(walk+1))) \
317 walk++; \
318 } \
319 } while (0)
320
321 for (walk = format; *walk != '\0'; walk++) {
322 if (*walk != '%') {
323 *(outwalk++) = *walk;
324 continue;
325 }
326
327 if (strncmp(walk+1, "status", strlen("status")) == 0) {
328 outwalk += sprintf(outwalk, "%s", statusbuf);
329 walk += strlen("status");
330 } else if (strncmp(walk+1, "percentage", strlen("percentage")) == 0) {
331 outwalk += sprintf(outwalk, "%s", percentagebuf);
332 walk += strlen("percentage");
333 } else if (strncmp(walk+1, "remaining", strlen("remaining")) == 0) {
334 outwalk += sprintf(outwalk, "%s", remainingbuf);
335 walk += strlen("remaining");
336 EAT_SPACE_FROM_OUTPUT_IF_EMPTY(remainingbuf);
337 } else if (strncmp(walk+1, "emptytime", strlen("emptytime")) == 0) {
338 outwalk += sprintf(outwalk, "%s", emptytimebuf);
339 walk += strlen("emptytime");
340 EAT_SPACE_FROM_OUTPUT_IF_EMPTY(emptytimebuf);
341 } else if (strncmp(walk+1, "consumption", strlen("consumption")) == 0) {
342 outwalk += sprintf(outwalk, "%s", consumptionbuf);
343 walk += strlen("consumption");
344 EAT_SPACE_FROM_OUTPUT_IF_EMPTY(consumptionbuf);
345 }
346 }
347
348 if (colorful_output)
349 END_COLOR;
350
351 OUTPUT_FULL_TEXT(buffer);
574 #define EAT_SPACE_FROM_OUTPUT_IF_EMPTY(_buf) \
575 do { \
576 if (strlen(_buf) == 0) { \
577 if (outwalk > buffer && isspace(outwalk[-1])) \
578 outwalk--; \
579 else if (isspace(*(walk + 1))) \
580 walk++; \
581 } \
582 } while (0)
583
584 for (walk = format; *walk != '\0'; walk++) {
585 if (*walk != '%') {
586 *(outwalk++) = *walk;
587 continue;
588 }
589
590 if (BEGINS_WITH(walk + 1, "status")) {
591 outwalk += sprintf(outwalk, "%s", statusbuf);
592 walk += strlen("status");
593 } else if (BEGINS_WITH(walk + 1, "percentage")) {
594 outwalk += sprintf(outwalk, "%s", percentagebuf);
595 walk += strlen("percentage");
596 } else if (BEGINS_WITH(walk + 1, "remaining")) {
597 outwalk += sprintf(outwalk, "%s", remainingbuf);
598 walk += strlen("remaining");
599 EAT_SPACE_FROM_OUTPUT_IF_EMPTY(remainingbuf);
600 } else if (BEGINS_WITH(walk + 1, "emptytime")) {
601 outwalk += sprintf(outwalk, "%s", emptytimebuf);
602 walk += strlen("emptytime");
603 EAT_SPACE_FROM_OUTPUT_IF_EMPTY(emptytimebuf);
604 } else if (BEGINS_WITH(walk + 1, "consumption")) {
605 outwalk += sprintf(outwalk, "%s", consumptionbuf);
606 walk += strlen("consumption");
607 EAT_SPACE_FROM_OUTPUT_IF_EMPTY(consumptionbuf);
608 }
609 }
610
611 if (colorful_output)
612 END_COLOR;
613
614 OUTPUT_FULL_TEXT(buffer);
352615 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <stdlib.h>
22 #include <limits.h>
33 #include <stdio.h>
77
88 #include "i3status.h"
99
10 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
10 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1111 #include <err.h>
1212 #include <sys/types.h>
1313 #include <sys/sysctl.h>
1414 #define TZ_ZEROC 2732
15 #define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10)
16 #define TZ_AVG(x) ((x) - TZ_ZEROC) / 10
15 #define TZ_KELVTOC(x) (((x)-TZ_ZEROC) / 10), abs(((x)-TZ_ZEROC) % 10)
16 #define TZ_AVG(x) ((x)-TZ_ZEROC) / 10
17 #endif
18
19 #if defined(__DragonFly__)
20 #include <sys/sysctl.h>
21 #include <sys/types.h>
22 #include <sys/sensors.h>
23 #define MUKTOC(v) ((v - 273150000) / 1000000.0)
1724 #endif
1825
1926 #if defined(__OpenBSD__)
3542 #define MUKTOC(v) ((v - 273150000) / 1000000.0)
3643 #endif
3744
38
39 static char *thermal_zone;
40
4145 /*
42 * Reads the CPU temperature from /sys/class/thermal/thermal_zone0/temp and
43 * returns the temperature in degree celcius.
46 * Reads the CPU temperature from /sys/class/thermal/thermal_zone%d/temp (or
47 * the user provided path) and returns the temperature in degree celcius.
4448 *
4549 */
4650 void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, int max_threshold) {
47 char *outwalk = buffer;
51 char *outwalk = buffer;
4852 #ifdef THERMAL_ZONE
49 const char *walk;
50 bool colorful_output = false;
51
52 if (thermal_zone == NULL) {
53 if (path == NULL)
54 asprintf(&thermal_zone, THERMAL_ZONE, zone);
55 else
56 asprintf(&thermal_zone, path, zone);
53 const char *walk;
54 bool colorful_output = false;
55 char *thermal_zone;
56
57 if (path == NULL)
58 asprintf(&thermal_zone, THERMAL_ZONE, zone);
59 else
60 asprintf(&thermal_zone, path, zone);
61
62 INSTANCE(thermal_zone);
63
64 for (walk = format; *walk != '\0'; walk++) {
65 if (*walk != '%') {
66 *(outwalk++) = *walk;
67 continue;
5768 }
58 path = thermal_zone;
59
60 INSTANCE(path);
61
62 for (walk = format; *walk != '\0'; walk++) {
63 if (*walk != '%') {
64 *(outwalk++) = *walk;
65 continue;
66 }
67
68 if (BEGINS_WITH(walk+1, "degrees")) {
69
70 if (BEGINS_WITH(walk + 1, "degrees")) {
6971 #if defined(LINUX)
70 static char buf[16];
71 long int temp;
72 if (!slurp(path, buf, sizeof(buf)))
73 goto error;
74 temp = strtol(buf, NULL, 10);
75 if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
76 *(outwalk++) = '?';
77 else {
78 if ((temp/1000) >= max_threshold) {
79 START_COLOR("color_bad");
80 colorful_output = true;
81 }
82 outwalk += sprintf(outwalk, "%ld", (temp/1000));
83 if (colorful_output) {
84 END_COLOR;
85 colorful_output = false;
86 }
87 }
88 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
89 int sysctl_rslt;
90 size_t sysctl_size = sizeof(sysctl_rslt);
91 if (sysctlbyname(path, &sysctl_rslt, &sysctl_size, NULL, 0))
92 goto error;
93
94 if (TZ_AVG(sysctl_rslt) >= max_threshold) {
95 START_COLOR("color_bad");
96 colorful_output = true;
97 }
98 outwalk += sprintf(outwalk, "%d.%d", TZ_KELVTOC(sysctl_rslt));
99 if (colorful_output) {
100 END_COLOR;
101 colorful_output = false;
102 }
72 static char buf[16];
73 long int temp;
74 if (!slurp(thermal_zone, buf, sizeof(buf)))
75 goto error;
76 temp = strtol(buf, NULL, 10);
77 if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
78 *(outwalk++) = '?';
79 else {
80 if ((temp / 1000) >= max_threshold) {
81 START_COLOR("color_bad");
82 colorful_output = true;
83 }
84 outwalk += sprintf(outwalk, "%ld", (temp / 1000));
85 if (colorful_output) {
86 END_COLOR;
87 colorful_output = false;
88 }
89 }
90 #elif defined(__DragonFly__)
91 struct sensor th_sensor;
92 size_t th_sensorlen;
93
94 th_sensorlen = sizeof(th_sensor);
95
96 if (sysctlbyname(thermal_zone, &th_sensor, &th_sensorlen, NULL, 0) == -1) {
97 perror("sysctlbyname");
98 goto error;
99 }
100 if (MUKTOC(th_sensor.value) >= max_threshold) {
101 START_COLOR("color_bad");
102 colorful_output = true;
103 }
104 outwalk += sprintf(outwalk, "%.2f", MUKTOC(th_sensor.value));
105 if (colorful_output) {
106 END_COLOR;
107 colorful_output = false;
108 }
109
110 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
111 int sysctl_rslt;
112 size_t sysctl_size = sizeof(sysctl_rslt);
113 if (sysctlbyname(thermal_zone, &sysctl_rslt, &sysctl_size, NULL, 0))
114 goto error;
115
116 if (TZ_AVG(sysctl_rslt) >= max_threshold) {
117 START_COLOR("color_bad");
118 colorful_output = true;
119 }
120 outwalk += sprintf(outwalk, "%d.%d", TZ_KELVTOC(sysctl_rslt));
121 if (colorful_output) {
122 END_COLOR;
123 colorful_output = false;
124 }
103125
104126 #elif defined(__OpenBSD__)
105 struct sensordev sensordev;
106 struct sensor sensor;
107 size_t sdlen, slen;
108 int dev, numt, mib[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 };
109
110 sdlen = sizeof(sensordev);
111 slen = sizeof(sensor);
112
113 for (dev = 0; ; dev++) {
127 struct sensordev sensordev;
128 struct sensor sensor;
129 size_t sdlen, slen;
130 int dev, numt, mib[5] = {CTL_HW, HW_SENSORS, 0, 0, 0};
131
132 sdlen = sizeof(sensordev);
133 slen = sizeof(sensor);
134
135 for (dev = 0;; dev++) {
114136 mib[2] = dev;
115137 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
116 if (errno == ENXIO)
138 if (errno == ENXIO)
139 continue;
140 if (errno == ENOENT)
141 break;
142 goto error;
143 }
144 /* 'path' is the node within the full path (defaults to acpitz0). */
145 if (BEGINS_WITH(sensordev.xname, thermal_zone)) {
146 mib[3] = SENSOR_TEMP;
147 /* Limit to temo0, but should retrieve from a full path... */
148 for (numt = 0; numt < 1 /*sensordev.maxnumt[SENSOR_TEMP]*/; numt++) {
149 mib[4] = numt;
150 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) {
151 if (errno != ENOENT) {
152 warn("sysctl");
117153 continue;
118 if (errno == ENOENT)
119 break;
120 goto error;
121 }
122 /* 'path' is the node within the full path (defaults to acpitz0). */
123 if (strncmp(sensordev.xname, path, strlen(path)) == 0) {
124 mib[3] = SENSOR_TEMP;
125 /* Limit to temo0, but should retrieve from a full path... */
126 for (numt = 0; numt < 1 /*sensordev.maxnumt[SENSOR_TEMP]*/; numt++) {
127 mib[4] = numt;
128 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) {
129 if (errno != ENOENT) {
130 warn("sysctl");
131 continue;
132 }
133 }
134 if ((int)MUKTOC(sensor.value) >= max_threshold) {
135 START_COLOR("color_bad");
136 colorful_output = true;
137 }
138
139 outwalk += sprintf(outwalk, "%.2f", MUKTOC(sensor.value));
140
141 if (colorful_output) {
142 END_COLOR;
143 colorful_output = false;
144 }
154 }
145155 }
146 }
147 }
156 if ((int)MUKTOC(sensor.value) >= max_threshold) {
157 START_COLOR("color_bad");
158 colorful_output = true;
159 }
160
161 outwalk += sprintf(outwalk, "%.2f", MUKTOC(sensor.value));
162
163 if (colorful_output) {
164 END_COLOR;
165 colorful_output = false;
166 }
167 }
168 }
169 }
148170 #elif defined(__NetBSD__)
149 int fd, rval;
150 bool err = false;
151 prop_dictionary_t dict;
152 prop_array_t array;
153 prop_object_iterator_t iter;
154 prop_object_iterator_t iter2;
155 prop_object_t obj, obj2, obj3;
156
157 fd = open("/dev/sysmon", O_RDONLY);
158 if (fd == -1)
159 goto error;
160
161 rval = prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict);
162 if (rval == -1) {
163 err = true;
164 goto error_netbsd1;
165 }
166
167 /* No drivers registered? */
168 if (prop_dictionary_count(dict) == 0) {
169 err = true;
170 goto error_netbsd2;
171 }
172
173 /* print sensors for all devices registered */
174 iter = prop_dictionary_iterator(dict);
175 if (iter == NULL) {
176 err = true;
177 goto error_netbsd2;
178 }
179
180 /* iterate over the dictionary returned by the kernel */
181 while ((obj = prop_object_iterator_next(iter)) != NULL) {
171 int fd, rval;
172 bool err = false;
173 prop_dictionary_t dict;
174 prop_array_t array;
175 prop_object_iterator_t iter;
176 prop_object_iterator_t iter2;
177 prop_object_t obj, obj2, obj3;
178
179 fd = open("/dev/sysmon", O_RDONLY);
180 if (fd == -1)
181 goto error;
182
183 rval = prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict);
184 if (rval == -1) {
185 err = true;
186 goto error_netbsd1;
187 }
188
189 /* No drivers registered? */
190 if (prop_dictionary_count(dict) == 0) {
191 err = true;
192 goto error_netbsd2;
193 }
194
195 iter = prop_dictionary_iterator(dict);
196 if (iter == NULL) {
197 err = true;
198 goto error_netbsd2;
199 }
200
201 /* iterate over the dictionary returned by the kernel */
202 while ((obj = prop_object_iterator_next(iter)) != NULL) {
203 /* skip this dict if it's not what we're looking for */
204 if ((strlen(prop_dictionary_keysym_cstring_nocopy(obj)) != strlen(thermal_zone)) ||
205 (strncmp(thermal_zone,
206 prop_dictionary_keysym_cstring_nocopy(obj),
207 strlen(thermal_zone)) != 0))
208 continue;
209
182210 array = prop_dictionary_get_keysym(dict, obj);
183211 if (prop_object_type(array) != PROP_TYPE_ARRAY) {
184212 err = true;
185213 goto error_netbsd3;
186214 }
215
187216 iter2 = prop_array_iterator(array);
188217 if (!iter2) {
189218 err = true;
190219 goto error_netbsd3;
191220 }
192221
193 /* iterate over the array of dictionaries */
222 /* iterate over array of dicts specific to target sensor */
194223 while ((obj2 = prop_object_iterator_next(iter2)) != NULL) {
195 obj3 = prop_dictionary_get(obj2, "description");
196 if (obj3 &&
197 strcmp(path, prop_string_cstring_nocopy(obj3)) == 0)
198 {
199 obj3 = prop_dictionary_get(obj2, "cur-value");
200 float temp = MUKTOC(prop_number_integer_value(obj3));
201 if ((int)temp >= max_threshold) {
202 START_COLOR("color_bad");
203 colorful_output = true;
204 }
205
206 outwalk += sprintf(outwalk, "%.2f", temp);
207
208 if (colorful_output) {
209 END_COLOR;
210 colorful_output = false;
211 }
212 break;
213 }
214
224 obj3 = prop_dictionary_get(obj2, "cur-value");
225
226 float temp = MUKTOC(prop_number_integer_value(obj3));
227 if ((int)temp >= max_threshold) {
228 START_COLOR("color_bad");
229 colorful_output = true;
230 }
231
232 outwalk += sprintf(outwalk, "%.2f", temp);
233
234 if (colorful_output) {
235 END_COLOR;
236 colorful_output = false;
237 }
238
239 break;
215240 }
216241 prop_object_iterator_release(iter2);
242 }
243 error_netbsd3:
244 prop_object_iterator_release(iter);
245 error_netbsd2:
246 prop_object_release(dict);
247 error_netbsd1:
248 close(fd);
249 if (err)
250 goto error;
251
252 #endif
253
254 walk += strlen("degrees");
217255 }
218 error_netbsd3:
219 prop_object_iterator_release(iter);
220 error_netbsd2:
221 prop_object_release(dict);
222 error_netbsd1:
223 close(fd);
224 if (err) goto error;
225
226 #endif
227
228
229 walk += strlen("degrees");
230 }
231 }
232 OUTPUT_FULL_TEXT(buffer);
233 return;
256 }
257
258 free(thermal_zone);
259
260 OUTPUT_FULL_TEXT(buffer);
261 return;
234262 error:
235263 #endif
236 OUTPUT_FULL_TEXT("cant read temp");
237 (void)fputs("i3status: Cannot read temperature. Verify that you have a thermal zone in /sys/class/thermal or disable the cpu_temperature module in your i3status config.\n", stderr);
264 free(thermal_zone);
265
266 OUTPUT_FULL_TEXT("cant read temp");
267 (void)fputs("i3status: Cannot read temperature. Verify that you have a thermal zone in /sys/class/thermal or disable the cpu_temperature module in your i3status config.\n", stderr);
238268 }
0 // vim:sw=8:sts=8:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <stdlib.h>
22 #include <limits.h>
33 #include <stdio.h>
2929 #include "i3status.h"
3030
3131 static int prev_total = 0;
32 static int prev_idle = 0;
32 static int prev_idle = 0;
3333
3434 /*
3535 * Reads the CPU utilization from /proc/stat and returns the usage as a
3737 *
3838 */
3939 void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format) {
40 const char *walk;
41 char *outwalk = buffer;
42 char buf[1024];
43 int curr_user = 0, curr_nice = 0, curr_system = 0, curr_idle = 0, curr_total;
44 int diff_idle, diff_total, diff_usage;
40 const char *walk;
41 char *outwalk = buffer;
42 char buf[1024];
43 int curr_user = 0, curr_nice = 0, curr_system = 0, curr_idle = 0, curr_total;
44 int diff_idle, diff_total, diff_usage;
4545
4646 #if defined(LINUX)
47 static char statpath[512];
48 strcpy(statpath, "/proc/stat");
49 if (!slurp(statpath, buf, sizeof(buf)) ||
50 sscanf(buf, "cpu %d %d %d %d", &curr_user, &curr_nice, &curr_system, &curr_idle) != 4)
51 goto error;
47 static char statpath[512];
48 strcpy(statpath, "/proc/stat");
49 if (!slurp(statpath, buf, sizeof(buf)) ||
50 sscanf(buf, "cpu %d %d %d %d", &curr_user, &curr_nice, &curr_system, &curr_idle) != 4)
51 goto error;
5252
53 curr_total = curr_user + curr_nice + curr_system + curr_idle;
54 diff_idle = curr_idle - prev_idle;
55 diff_total = curr_total - prev_total;
56 diff_usage = (diff_total ? (1000 * (diff_total - diff_idle)/diff_total + 5)/10 : 0);
57 prev_total = curr_total;
58 prev_idle = curr_idle;
53 curr_total = curr_user + curr_nice + curr_system + curr_idle;
54 diff_idle = curr_idle - prev_idle;
55 diff_total = curr_total - prev_total;
56 diff_usage = (diff_total ? (1000 * (diff_total - diff_idle) / diff_total + 5) / 10 : 0);
57 prev_total = curr_total;
58 prev_idle = curr_idle;
5959 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
6060
6161 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
62 size_t size;
63 long cp_time[CPUSTATES];
64 size = sizeof cp_time;
65 if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) < 0)
66 goto error;
62 size_t size;
63 long cp_time[CPUSTATES];
64 size = sizeof cp_time;
65 if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) < 0)
66 goto error;
6767 #else
68 /* This information is taken from the boot cpu, any other cpus are currently ignored. */
69 long cp_time[CPUSTATES];
70 int mib[2];
71 size_t size = sizeof(cp_time);
68 /* This information is taken from the boot cpu, any other cpus are currently ignored. */
69 long cp_time[CPUSTATES];
70 int mib[2];
71 size_t size = sizeof(cp_time);
7272
73 mib[0] = CTL_KERN;
74 mib[1] = KERN_CPTIME;
73 mib[0] = CTL_KERN;
74 mib[1] = KERN_CPTIME;
7575
76 if (sysctl(mib, 2, cp_time, &size, NULL, 0))
77 goto error;
76 if (sysctl(mib, 2, cp_time, &size, NULL, 0))
77 goto error;
7878 #endif
7979
80 curr_user = cp_time[CP_USER];
81 curr_nice = cp_time[CP_NICE];
82 curr_system = cp_time[CP_SYS];
83 curr_idle = cp_time[CP_IDLE];
84 curr_total = curr_user + curr_nice + curr_system + curr_idle;
85 diff_idle = curr_idle - prev_idle;
86 diff_total = curr_total - prev_total;
87 diff_usage = (diff_total ? (1000 * (diff_total - diff_idle)/diff_total + 5)/10 : 0);
88 prev_total = curr_total;
89 prev_idle = curr_idle;
80 curr_user = cp_time[CP_USER];
81 curr_nice = cp_time[CP_NICE];
82 curr_system = cp_time[CP_SYS];
83 curr_idle = cp_time[CP_IDLE];
84 curr_total = curr_user + curr_nice + curr_system + curr_idle;
85 diff_idle = curr_idle - prev_idle;
86 diff_total = curr_total - prev_total;
87 diff_usage = (diff_total ? (1000 * (diff_total - diff_idle) / diff_total + 5) / 10 : 0);
88 prev_total = curr_total;
89 prev_idle = curr_idle;
9090 #else
91 goto error;
91 goto error;
9292 #endif
93 for (walk = format; *walk != '\0'; walk++) {
94 if (*walk != '%') {
95 *(outwalk++) = *walk;
96 continue;
97 }
98
99 if (strncmp(walk+1, "usage", strlen("usage")) == 0) {
100 outwalk += sprintf(outwalk, "%02d%%", diff_usage);
101 walk += strlen("usage");
102 }
93 for (walk = format; *walk != '\0'; walk++) {
94 if (*walk != '%') {
95 *(outwalk++) = *walk;
96 continue;
10397 }
10498
105 OUTPUT_FULL_TEXT(buffer);
106 return;
99 if (BEGINS_WITH(walk + 1, "usage")) {
100 outwalk += sprintf(outwalk, "%02d%%", diff_usage);
101 walk += strlen("usage");
102 }
103 }
104
105 OUTPUT_FULL_TEXT(buffer);
106 return;
107107 error:
108 OUTPUT_FULL_TEXT("cant read cpu usage");
109 (void)fputs("i3status: Cannot read CPU usage\n", stderr);
108 OUTPUT_FULL_TEXT("cant read cpu usage");
109 (void)fputs("i3status: Cannot read CPU usage\n", stderr);
110110 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <time.h>
22 #include <stdio.h>
33 #include <stdlib.h>
99
1010 /* define fixed output-Strings */
1111 char *season_long[5] = {
12 "Chaos",
13 "Discord",
14 "Confusion",
15 "Bureaucracy",
16 "The Aftermath"
17 };
12 "Chaos",
13 "Discord",
14 "Confusion",
15 "Bureaucracy",
16 "The Aftermath"};
1817
1918 char *season_short[5] = {
20 "Chs",
21 "Dsc",
22 "Cfn",
23 "Bcy",
24 "Afm"
25 };
19 "Chs",
20 "Dsc",
21 "Cfn",
22 "Bcy",
23 "Afm"};
2624
2725 char *day_long[5] = {
28 "Sweetmorn",
29 "Boomtime",
30 "Pungenday",
31 "Prickle-Prickle",
32 "Setting Orange"
33 };
26 "Sweetmorn",
27 "Boomtime",
28 "Pungenday",
29 "Prickle-Prickle",
30 "Setting Orange"};
3431
3532 char *day_short[5] = {
36 "SM",
37 "BT",
38 "PD",
39 "PP",
40 "SO"
41 };
33 "SM",
34 "BT",
35 "PD",
36 "PP",
37 "SO"};
4238
4339 char *holidays[10] = {
44 "Mungday",
45 "Mojoday",
46 "Syaday",
47 "Zaraday",
48 "Maladay",
49 "Chaoflux",
50 "Discoflux",
51 "Confuflux",
52 "Bureflux",
53 "Afflux"
54 };
40 "Mungday",
41 "Mojoday",
42 "Syaday",
43 "Zaraday",
44 "Maladay",
45 "Chaoflux",
46 "Discoflux",
47 "Confuflux",
48 "Bureflux",
49 "Afflux"};
5550
5651 /* A helper-struct, taking the discordian date */
5752 struct disc_time {
58 int year;
59 int season;
60 int week_day;
61 int season_day;
62 int st_tibs_day;
53 int year;
54 int season;
55 int week_day;
56 int season_day;
57 int st_tibs_day;
6358 };
6459
6560 /* Print the date *dt in format *format */
6661 static int format_output(char *outwalk, char *format, struct disc_time *dt) {
67 char *orig_outwalk = outwalk;
68 char *i;
69 char *tibs_end = 0;
70
71 for (i = format; *i != '\0'; i++) {
72 if (*i != '%') {
73 *(outwalk++) = *i;
74 continue;
75 }
76 switch (*(i+1)) {
77 /* Weekday in long and abbreviation */
78 case 'A':
79 outwalk += sprintf(outwalk, "%s", day_long[dt->week_day]);
80 break;
81 case 'a':
82 outwalk += sprintf(outwalk, "%s", day_short[dt->week_day]);
83 break;
84 /* Season in long and abbreviation */
85 case 'B':
86 outwalk += sprintf(outwalk, "%s", season_long[dt->season]);
87 break;
88 case 'b':
89 outwalk += sprintf(outwalk, "%s", season_short[dt->season]);
90 break;
91 /* Day of the season (ordinal and cardinal) */
92 case 'd':
93 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
94 break;
95 case 'e':
96 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
97 if (dt->season_day > 9 && dt->season_day < 13) {
98 outwalk += sprintf(outwalk, "th");
99 break;
100 }
101
102 switch (dt->season_day % 10) {
103 case 0:
104 outwalk += sprintf(outwalk, "st");
105 break;
106 case 1:
107 outwalk += sprintf(outwalk, "nd");
108 break;
109 case 2:
110 outwalk += sprintf(outwalk, "rd");
111 break;
112 default:
113 outwalk += sprintf(outwalk, "th");
114 break;
115 }
116 break;
117 /* YOLD */
118 case 'Y':
119 outwalk += sprintf(outwalk, "%d", dt->year);
120 break;
121 /* Holidays */
122 case 'H':
123 if (dt->season_day == 4) {
124 outwalk += sprintf(outwalk, "%s", holidays[dt->season]);
125 }
126 if (dt->season_day == 49) {
127 outwalk += sprintf(outwalk, "%s", holidays[dt->season + 5]);
128 }
129 break;
130 /* Stop parsing the format string, except on Holidays */
131 case 'N':
132 if (dt->season_day != 4 && dt->season_day != 49) {
133 return (outwalk - orig_outwalk);
134 }
135 break;
136 /* Newline- and Tabbing-characters */
137 case 'n':
138 outwalk += sprintf(outwalk, "\n");
139 break;
140 case 't':
141 outwalk += sprintf(outwalk, "\t");
142 break;
143 /* The St. Tib's Day replacement */
144 case '{':
145 tibs_end = strstr(i, "%}");
146 if (tibs_end == NULL) {
147 i++;
148 break;
149 }
150 if (dt->st_tibs_day) {
151 /* We outpt "St. Tib's Day... */
152 outwalk += sprintf(outwalk, "St. Tib's Day");
153 } else {
154 /* ...or parse the substring between %{ and %} ... */
155 *tibs_end = '\0';
156 outwalk += format_output(outwalk, i + 2, dt);
157 *tibs_end = '%';
158 }
159 /* ...and continue with the rest */
160 i = tibs_end;
161 break;
162 case '}':
163 i++;
164 break;
165 default:
166 /* No escape-sequence, so we just skip */
167 outwalk += sprintf(outwalk, "%%%c", *(i+1));
168 break;
169 }
62 char *orig_outwalk = outwalk;
63 char *i;
64 char *tibs_end = 0;
65
66 for (i = format; *i != '\0'; i++) {
67 if (*i != '%') {
68 *(outwalk++) = *i;
69 continue;
70 }
71 switch (*(i + 1)) {
72 /* Weekday in long and abbreviation */
73 case 'A':
74 outwalk += sprintf(outwalk, "%s", day_long[dt->week_day]);
75 break;
76 case 'a':
77 outwalk += sprintf(outwalk, "%s", day_short[dt->week_day]);
78 break;
79 /* Season in long and abbreviation */
80 case 'B':
81 outwalk += sprintf(outwalk, "%s", season_long[dt->season]);
82 break;
83 case 'b':
84 outwalk += sprintf(outwalk, "%s", season_short[dt->season]);
85 break;
86 /* Day of the season (ordinal and cardinal) */
87 case 'd':
88 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
89 break;
90 case 'e':
91 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
92 if (dt->season_day > 9 && dt->season_day < 13) {
93 outwalk += sprintf(outwalk, "th");
94 break;
95 }
96
97 switch (dt->season_day % 10) {
98 case 0:
99 outwalk += sprintf(outwalk, "st");
100 break;
101 case 1:
102 outwalk += sprintf(outwalk, "nd");
103 break;
104 case 2:
105 outwalk += sprintf(outwalk, "rd");
106 break;
107 default:
108 outwalk += sprintf(outwalk, "th");
109 break;
110 }
111 break;
112 /* YOLD */
113 case 'Y':
114 outwalk += sprintf(outwalk, "%d", dt->year);
115 break;
116 /* Holidays */
117 case 'H':
118 if (dt->season_day == 4) {
119 outwalk += sprintf(outwalk, "%s", holidays[dt->season]);
120 }
121 if (dt->season_day == 49) {
122 outwalk += sprintf(outwalk, "%s", holidays[dt->season + 5]);
123 }
124 break;
125 /* Stop parsing the format string, except on Holidays */
126 case 'N':
127 if (dt->season_day != 4 && dt->season_day != 49) {
128 return (outwalk - orig_outwalk);
129 }
130 break;
131 /* Newline- and Tabbing-characters */
132 case 'n':
133 outwalk += sprintf(outwalk, "\n");
134 break;
135 case 't':
136 outwalk += sprintf(outwalk, "\t");
137 break;
138 /* The St. Tib's Day replacement */
139 case '{':
140 tibs_end = strstr(i, "%}");
141 if (tibs_end == NULL) {
142 i++;
143 break;
144 }
145 if (dt->st_tibs_day) {
146 /* We outpt "St. Tib's Day... */
147 outwalk += sprintf(outwalk, "St. Tib's Day");
148 } else {
149 /* ...or parse the substring between %{ and %} ... */
150 *tibs_end = '\0';
151 outwalk += format_output(outwalk, i + 2, dt);
152 *tibs_end = '%';
153 }
154 /* ...and continue with the rest */
155 i = tibs_end;
156 break;
157 case '}':
170158 i++;
159 break;
160 default:
161 /* No escape-sequence, so we just skip */
162 outwalk += sprintf(outwalk, "%%%c", *(i + 1));
163 break;
171164 }
172 return (outwalk - orig_outwalk);
165 i++;
166 }
167 return (outwalk - orig_outwalk);
173168 }
174169
175170 /* Get the current date and convert it to discordian */
176171 struct disc_time *get_ddate(struct tm *current_tm) {
177 static struct disc_time dt;
178
179 if (current_tm == NULL)
180 return NULL;
181
182 /* We have to know, whether we have to insert St. Tib's Day, so whether it's a leap
183 year in gregorian calendar */
184 int is_leap_year = !(current_tm->tm_year % 4) &&
185 (!(current_tm->tm_year % 400) || current_tm->tm_year % 100);
186
187 /* If St. Tib's Day has passed, it will be necessary to skip a day. */
188 int yday = current_tm->tm_yday;
189
190 if (is_leap_year && yday == 59) {
191 /* On St. Tibs Day we don't have to define a date */
192 dt.st_tibs_day = 1;
193 } else {
194 dt.st_tibs_day = 0;
195 if (is_leap_year && yday > 59)
196 yday -= 1;
197
198 dt.season_day = yday % 73;
199 dt.week_day = yday % 5;
200 }
201 dt.year = current_tm->tm_year + 3066;
202 dt.season = yday / 73;
203 return &dt;
172 static struct disc_time dt;
173
174 if (current_tm == NULL)
175 return NULL;
176
177 /* We have to know, whether we have to insert St. Tib's Day, so whether it's a leap
178 * year in gregorian calendar */
179 int is_leap_year = !(current_tm->tm_year % 4) &&
180 (!(current_tm->tm_year % 400) || current_tm->tm_year % 100);
181
182 /* If St. Tib's Day has passed, it will be necessary to skip a day. */
183 int yday = current_tm->tm_yday;
184
185 if (is_leap_year && yday == 59) {
186 /* On St. Tibs Day we don't have to define a date */
187 dt.st_tibs_day = 1;
188 } else {
189 dt.st_tibs_day = 0;
190 if (is_leap_year && yday > 59)
191 yday -= 1;
192
193 dt.season_day = yday % 73;
194 dt.week_day = yday % 5;
195 }
196 dt.year = current_tm->tm_year + 3066;
197 dt.season = yday / 73;
198 return &dt;
204199 }
205200
206201 void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t) {
207 char *outwalk = buffer;
208 static char *form = NULL;
209 struct tm current_tm;
210 struct disc_time *dt;
211 set_timezone(NULL); /* Use local time. */
212 localtime_r(&t, &current_tm);
213 if ((dt = get_ddate(&current_tm)) == NULL)
214 return;
215 if (form == NULL)
216 if ((form = malloc(strlen(format) + 1)) == NULL)
217 return;
218 strcpy(form, format);
219 outwalk += format_output(outwalk, form, dt);
220 OUTPUT_FULL_TEXT(buffer);
202 char *outwalk = buffer;
203 static char *form = NULL;
204 struct tm current_tm;
205 struct disc_time *dt;
206 set_timezone(NULL); /* Use local time. */
207 localtime_r(&t, &current_tm);
208 if ((dt = get_ddate(&current_tm)) == NULL)
209 return;
210 if (form == NULL)
211 if ((form = malloc(strlen(format) + 1)) == NULL)
212 return;
213 strcpy(form, format);
214 outwalk += format_output(outwalk, form, dt);
215 OUTPUT_FULL_TEXT(buffer);
221216 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <stdio.h>
22 #include <stdlib.h>
33 #include <string.h>
44 #include <ctype.h>
5 #include <mntent.h>
56 #include <stdint.h>
7 #include <sys/stat.h>
68 #include <sys/statvfs.h>
79 #include <sys/types.h>
810 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || (__OpenBSD__) || defined(__DragonFly__)
1921
2022 #define MAX_EXPONENT 4
2123
22 static const char * const iec_symbols[MAX_EXPONENT+1] = {"", "Ki", "Mi", "Gi", "Ti"};
23 static const char * const si_symbols[MAX_EXPONENT+1] = {"", "k", "M", "G", "T"};
24 static const char * const custom_symbols[MAX_EXPONENT+1] = {"", "K", "M", "G", "T"};
24 static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"};
25 static const char *const si_symbols[MAX_EXPONENT + 1] = {"", "k", "M", "G", "T"};
26 static const char *const custom_symbols[MAX_EXPONENT + 1] = {"", "K", "M", "G", "T"};
2527
2628 /*
2729 * Formats bytes according to the given base and set of symbols.
2830 *
2931 */
30 static int format_bytes(char *outwalk, uint64_t bytes, uint64_t base, const char * const symbols[]) {
31 double size = bytes;
32 int exponent = 0;
33 while (size >= base && exponent < MAX_EXPONENT) {
34 size /= base;
35 exponent += 1;
36 }
37 return sprintf(outwalk, "%.1f %sB", size, symbols[exponent]);
32 static int format_bytes(char *outwalk, uint64_t bytes, uint64_t base, const char *const symbols[]) {
33 double size = bytes;
34 int exponent = 0;
35 while (size >= base && exponent < MAX_EXPONENT) {
36 size /= base;
37 exponent += 1;
38 }
39 return sprintf(outwalk, "%.1f %sB", size, symbols[exponent]);
3840 }
3941
4042 /*
4244 *
4345 */
4446 static int print_bytes_human(char *outwalk, uint64_t bytes, const char *prefix_type) {
45 if (strncmp(prefix_type, "decimal", strlen(prefix_type)) == 0) {
46 return format_bytes(outwalk, bytes, DECIMAL_BASE, si_symbols);
47 } else if (strncmp(prefix_type, "custom", strlen(prefix_type)) == 0) {
48 return format_bytes(outwalk, bytes, BINARY_BASE, custom_symbols);
49 } else {
50 return format_bytes(outwalk, bytes, BINARY_BASE, iec_symbols);
51 }
47 if (strcasecmp(prefix_type, "decimal") == 0) {
48 return format_bytes(outwalk, bytes, DECIMAL_BASE, si_symbols);
49 } else if (strcasecmp(prefix_type, "custom") == 0) {
50 return format_bytes(outwalk, bytes, BINARY_BASE, custom_symbols);
51 } else {
52 return format_bytes(outwalk, bytes, BINARY_BASE, iec_symbols);
53 }
54 }
55
56 /*
57 * Determines whether remaining bytes are below given threshold.
58 *
59 */
60 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__)
61 static bool below_threshold(struct statfs buf, const char *prefix_type, const char *threshold_type, const double low_threshold) {
62 #else
63 static bool below_threshold(struct statvfs buf, const char *prefix_type, const char *threshold_type, const double low_threshold) {
64 #endif
65 if (strcasecmp(threshold_type, "percentage_free") == 0) {
66 return 100.0 * (double)buf.f_bfree / (double)buf.f_blocks < low_threshold;
67 } else if (strcasecmp(threshold_type, "percentage_avail") == 0) {
68 return 100.0 * (double)buf.f_bavail / (double)buf.f_blocks < low_threshold;
69 } else if (strcasecmp(threshold_type, "bytes_free") == 0) {
70 return (double)buf.f_bsize * (double)buf.f_bfree < low_threshold;
71 } else if (strcasecmp(threshold_type, "bytes_avail") == 0) {
72 return (double)buf.f_bsize * (double)buf.f_bavail < low_threshold;
73 } else if (threshold_type[0] != '\0' && strncasecmp(threshold_type + 1, "bytes_", strlen("bytes_")) == 0) {
74 uint64_t base = strcasecmp(prefix_type, "decimal") == 0 ? DECIMAL_BASE : BINARY_BASE;
75 double factor = 1;
76
77 switch (threshold_type[0]) {
78 case 'T':
79 case 't':
80 factor *= base;
81 case 'G':
82 case 'g':
83 factor *= base;
84 case 'M':
85 case 'm':
86 factor *= base;
87 case 'K':
88 case 'k':
89 factor *= base;
90 break;
91 default:
92 return false;
93 }
94
95 if (strcasecmp(threshold_type + 1, "bytes_free") == 0) {
96 return (double)buf.f_bsize * (double)buf.f_bfree < low_threshold * factor;
97 } else if (strcasecmp(threshold_type + 1, "bytes_avail") == 0) {
98 return (double)buf.f_bsize * (double)buf.f_bavail < low_threshold * factor;
99 }
100 }
101
102 return false;
52103 }
53104
54105 /*
56107 * human readable manner.
57108 *
58109 */
59 void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format, const char *prefix_type) {
60 const char *walk;
61 char *outwalk = buffer;
62
63 INSTANCE(path);
110 void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format, const char *format_not_mounted, const char *prefix_type, const char *threshold_type, const double low_threshold) {
111 const char *walk;
112 char *outwalk = buffer;
113 bool colorful_output = false;
114
115 INSTANCE(path);
64116
65117 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__)
66 struct statfs buf;
67
68 if (statfs(path, &buf) == -1)
69 return;
118 struct statfs buf;
119
120 if (statfs(path, &buf) == -1)
121 return;
70122 #else
71 struct statvfs buf;
72
73 if (statvfs(path, &buf) == -1)
74 return;
123 struct statvfs buf;
124
125 if (statvfs(path, &buf) == -1)
126 return;
127
128 if (format_not_mounted != NULL) {
129 FILE *mntentfile = setmntent("/etc/mtab", "r");
130 struct mntent *m;
131 bool found = false;
132
133 while ((m = getmntent(mntentfile)) != NULL) {
134 if (strcmp(m->mnt_dir, path) == 0) {
135 found = true;
136 break;
137 }
138 }
139 endmntent(mntentfile);
140
141 if (!found) {
142 format = format_not_mounted;
143 }
144 }
75145 #endif
76146
77 for (walk = format; *walk != '\0'; walk++) {
78 if (*walk != '%') {
79 *(outwalk++) = *walk;
80 continue;
81 }
82
83 if (BEGINS_WITH(walk+1, "free")) {
84 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_bfree, prefix_type);
85 walk += strlen("free");
86 }
87
88 if (BEGINS_WITH(walk+1, "used")) {
89 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * ((uint64_t)buf.f_blocks - (uint64_t)buf.f_bfree), prefix_type);
90 walk += strlen("used");
91 }
92
93 if (BEGINS_WITH(walk+1, "total")) {
94 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_blocks, prefix_type);
95 walk += strlen("total");
96 }
97
98 if (BEGINS_WITH(walk+1, "avail")) {
99 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_bavail, prefix_type);
100 walk += strlen("avail");
101 }
102
103 if (BEGINS_WITH(walk+1, "percentage_free")) {
104 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)buf.f_bfree / (double)buf.f_blocks);
105 walk += strlen("percentage_free");
106 }
107
108 if (BEGINS_WITH(walk+1, "percentage_used_of_avail")) {
109 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)(buf.f_blocks - buf.f_bavail) / (double)buf.f_blocks);
110 walk += strlen("percentage_used_of_avail");
111 }
112
113 if (BEGINS_WITH(walk+1, "percentage_used")) {
114 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)(buf.f_blocks - buf.f_bfree) / (double)buf.f_blocks);
115 walk += strlen("percentage_used");
116 }
117
118 if (BEGINS_WITH(walk+1, "percentage_avail")) {
119 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)buf.f_bavail / (double)buf.f_blocks);
120 walk += strlen("percentage_avail");
121 }
122 }
123
124 *outwalk = '\0';
125 OUTPUT_FULL_TEXT(buffer);
126 }
147 if (low_threshold > 0 && below_threshold(buf, prefix_type, threshold_type, low_threshold)) {
148 START_COLOR("color_bad");
149 colorful_output = true;
150 }
151
152 for (walk = format; *walk != '\0'; walk++) {
153 if (*walk != '%') {
154 *(outwalk++) = *walk;
155 continue;
156 }
157
158 if (BEGINS_WITH(walk + 1, "free")) {
159 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_bfree, prefix_type);
160 walk += strlen("free");
161 }
162
163 if (BEGINS_WITH(walk + 1, "used")) {
164 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * ((uint64_t)buf.f_blocks - (uint64_t)buf.f_bfree), prefix_type);
165 walk += strlen("used");
166 }
167
168 if (BEGINS_WITH(walk + 1, "total")) {
169 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_blocks, prefix_type);
170 walk += strlen("total");
171 }
172
173 if (BEGINS_WITH(walk + 1, "avail")) {
174 outwalk += print_bytes_human(outwalk, (uint64_t)buf.f_bsize * (uint64_t)buf.f_bavail, prefix_type);
175 walk += strlen("avail");
176 }
177
178 if (BEGINS_WITH(walk + 1, "percentage_free")) {
179 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)buf.f_bfree / (double)buf.f_blocks);
180 walk += strlen("percentage_free");
181 }
182
183 if (BEGINS_WITH(walk + 1, "percentage_used_of_avail")) {
184 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)(buf.f_blocks - buf.f_bavail) / (double)buf.f_blocks);
185 walk += strlen("percentage_used_of_avail");
186 }
187
188 if (BEGINS_WITH(walk + 1, "percentage_used")) {
189 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)(buf.f_blocks - buf.f_bfree) / (double)buf.f_blocks);
190 walk += strlen("percentage_used");
191 }
192
193 if (BEGINS_WITH(walk + 1, "percentage_avail")) {
194 outwalk += sprintf(outwalk, "%.01f%%", 100.0 * (double)buf.f_bavail / (double)buf.f_blocks);
195 walk += strlen("percentage_avail");
196 }
197 }
198
199 if (colorful_output)
200 END_COLOR;
201
202 *outwalk = '\0';
203 OUTPUT_FULL_TEXT(buffer);
204 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <string.h>
22 #include <limits.h>
33 #include <stdio.h>
1515 #if defined(LINUX)
1616 #include <linux/ethtool.h>
1717 #include <linux/sockios.h>
18 #define PART_ETHSPEED "E: %s (%d Mbit/s)"
18 #define PART_ETHSPEED "E: %s (%d Mbit/s)"
1919 #endif
2020
2121 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
2222 #include <net/if_media.h>
23 #define IFM_TYPE_MATCH(dt, t) \
24 (IFM_TYPE((dt)) == 0 || IFM_TYPE((dt)) == IFM_TYPE((t)))
23 #define IFM_TYPE_MATCH(dt, t) \
24 (IFM_TYPE((dt)) == 0 || IFM_TYPE((dt)) == IFM_TYPE((t)))
2525
26 #define PART_ETHSPEED "E: %s (%s)"
26 #define PART_ETHSPEED "E: %s (%s)"
2727 #endif
2828
2929 #if defined(__OpenBSD__) || defined(__NetBSD__)
3333
3434 static int print_eth_speed(char *outwalk, const char *interface) {
3535 #if defined(LINUX)
36 /* This code path requires root privileges */
37 int ethspeed = 0;
38 struct ifreq ifr;
39 struct ethtool_cmd ecmd;
36 /* This code path requires root privileges */
37 int ethspeed = 0;
38 struct ifreq ifr;
39 struct ethtool_cmd ecmd;
4040
41 ecmd.cmd = ETHTOOL_GSET;
42 (void)memset(&ifr, 0, sizeof(ifr));
43 ifr.ifr_data = (caddr_t)&ecmd;
44 (void)strcpy(ifr.ifr_name, interface);
45 if (ioctl(general_socket, SIOCETHTOOL, &ifr) == 0) {
46 ethspeed = (ecmd.speed == USHRT_MAX ? 0 : ecmd.speed);
47 return sprintf(outwalk, "%d Mbit/s", ethspeed);
48 } else return sprintf(outwalk, "?");
41 ecmd.cmd = ETHTOOL_GSET;
42 (void)memset(&ifr, 0, sizeof(ifr));
43 ifr.ifr_data = (caddr_t)&ecmd;
44 (void)strcpy(ifr.ifr_name, interface);
45 if (ioctl(general_socket, SIOCETHTOOL, &ifr) == 0) {
46 ethspeed = (ecmd.speed == USHRT_MAX ? 0 : ecmd.speed);
47 return sprintf(outwalk, "%d Mbit/s", ethspeed);
48 } else
49 return sprintf(outwalk, "?");
4950 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
50 char *ethspeed;
51 struct ifmediareq ifm;
52 (void)memset(&ifm, 0, sizeof(ifm));
53 (void)strncpy(ifm.ifm_name, interface, sizeof(ifm.ifm_name));
54 int ret = ioctl(general_socket, SIOCGIFMEDIA, (caddr_t)&ifm);
51 char *ethspeed;
52 struct ifmediareq ifm;
53 (void)memset(&ifm, 0, sizeof(ifm));
54 (void)strncpy(ifm.ifm_name, interface, sizeof(ifm.ifm_name));
55 int ret = ioctl(general_socket, SIOCGIFMEDIA, (caddr_t)&ifm);
5556
56 /* Get the description of the media type, partially taken from
57 * FreeBSD's ifconfig */
58 const struct ifmedia_description *desc;
59 struct ifmedia_description ifm_subtype_descriptions[] =
60 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
57 /* Get the description of the media type, partially taken from
58 * FreeBSD's ifconfig */
59 const struct ifmedia_description *desc;
60 struct ifmedia_description ifm_subtype_descriptions[] =
61 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
6162
62 for (desc = ifm_subtype_descriptions;
63 desc->ifmt_string != NULL;
64 desc++) {
65 if (IFM_TYPE_MATCH(desc->ifmt_word, ifm.ifm_active) &&
66 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifm.ifm_active))
67 break;
68 }
69 ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
70 return sprintf(outwalk, "%s", ethspeed);
63 for (desc = ifm_subtype_descriptions;
64 desc->ifmt_string != NULL;
65 desc++) {
66 if (IFM_TYPE_MATCH(desc->ifmt_word, ifm.ifm_active) &&
67 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifm.ifm_active))
68 break;
69 }
70 ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
71 return sprintf(outwalk, "%s", ethspeed);
7172 #elif defined(__OpenBSD__) || defined(__NetBSD__)
72 char *ethspeed;
73 struct ifmediareq ifmr;
73 char *ethspeed;
74 struct ifmediareq ifmr;
7475
75 (void) memset(&ifmr, 0, sizeof(ifmr));
76 (void) strlcpy(ifmr.ifm_name, interface, sizeof(ifmr.ifm_name));
76 (void)memset(&ifmr, 0, sizeof(ifmr));
77 (void)strlcpy(ifmr.ifm_name, interface, sizeof(ifmr.ifm_name));
7778
78 if (ioctl(general_socket, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
79 if (errno != E2BIG)
80 return sprintf(outwalk, "?");
81 }
79 if (ioctl(general_socket, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
80 if (errno != E2BIG)
81 return sprintf(outwalk, "?");
82 }
8283
83 struct ifmedia_description *desc;
84 struct ifmedia_description ifm_subtype_descriptions[] =
85 IFM_SUBTYPE_DESCRIPTIONS;
84 struct ifmedia_description *desc;
85 struct ifmedia_description ifm_subtype_descriptions[] =
86 IFM_SUBTYPE_DESCRIPTIONS;
8687
87 for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL; desc++) {
88 /*
88 for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL; desc++) {
89 /*
8990 * Skip these non-informative values and go right ahead to the
9091 * actual speeds.
9192 */
92 if (strncmp(desc->ifmt_string, "autoselect", strlen("autoselect")) == 0 ||
93 strncmp(desc->ifmt_string, "auto", strlen("auto")) == 0)
94 continue;
93 if (BEGINS_WITH(desc->ifmt_string, "autoselect") ||
94 BEGINS_WITH(desc->ifmt_string, "auto"))
95 continue;
9596
96 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmr.ifm_active) &&
97 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifmr.ifm_active))
98 break;
99 }
100 ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
101 return sprintf(outwalk, "%s", ethspeed);
97 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmr.ifm_active) &&
98 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifmr.ifm_active))
99 break;
100 }
101 ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
102 return sprintf(outwalk, "%s", ethspeed);
102103
103104 #else
104 return sprintf(outwalk, "?");
105 return sprintf(outwalk, "?");
105106 #endif
106107 }
107108
110111 *
111112 */
112113 void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
113 const char *walk;
114 const char *ip_address = get_ip_addr(interface);
115 char *outwalk = buffer;
114 const char *walk;
115 const char *ip_address = get_ip_addr(interface);
116 char *outwalk = buffer;
116117
117 INSTANCE(interface);
118 INSTANCE(interface);
118119
119 if (ip_address == NULL) {
120 START_COLOR("color_bad");
121 outwalk += sprintf(outwalk, "%s", format_down);
122 goto out;
120 if (ip_address == NULL) {
121 START_COLOR("color_bad");
122 outwalk += sprintf(outwalk, "%s", format_down);
123 goto out;
124 }
125
126 START_COLOR("color_good");
127
128 for (walk = format_up; *walk != '\0'; walk++) {
129 if (*walk != '%') {
130 *(outwalk++) = *walk;
131 continue;
123132 }
124133
125 START_COLOR("color_good");
126
127 for (walk = format_up; *walk != '\0'; walk++) {
128 if (*walk != '%') {
129 *(outwalk++) = *walk;
130 continue;
131 }
132
133 if (strncmp(walk+1, "ip", strlen("ip")) == 0) {
134 outwalk += sprintf(outwalk, "%s", ip_address);
135 walk += strlen("ip");
136 } else if (strncmp(walk+1, "speed", strlen("speed")) == 0) {
137 outwalk += print_eth_speed(outwalk, interface);
138 walk += strlen("speed");
139 }
134 if (BEGINS_WITH(walk + 1, "ip")) {
135 outwalk += sprintf(outwalk, "%s", ip_address);
136 walk += strlen("ip");
137 } else if (BEGINS_WITH(walk + 1, "speed")) {
138 outwalk += print_eth_speed(outwalk, interface);
139 walk += strlen("speed");
140140 }
141 }
141142
142143 out:
143 END_COLOR;
144 OUTPUT_FULL_TEXT(buffer);
144 END_COLOR;
145 OUTPUT_FULL_TEXT(buffer);
145146 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <sys/types.h>
22 #include <sys/socket.h>
33 #include <netinet/in.h>
1717 *
1818 */
1919 const char *get_ip_addr(const char *interface) {
20 static char part[512];
21 socklen_t len = sizeof(struct sockaddr_in);
22 memset(part, 0, sizeof(part));
20 static char part[512];
21 socklen_t len = sizeof(struct sockaddr_in);
22 memset(part, 0, sizeof(part));
2323
24 struct ifaddrs *ifaddr, *addrp;
25 bool found = false;
24 struct ifaddrs *ifaddr, *addrp;
25 bool found = false;
2626
27 getifaddrs(&ifaddr);
27 getifaddrs(&ifaddr);
2828
29 if (ifaddr == NULL)
30 return NULL;
29 if (ifaddr == NULL)
30 return NULL;
3131
32 /* Skip until we are at the AF_INET address of interface */
33 for (addrp = ifaddr;
32 /* Skip until we are at the AF_INET address of interface */
33 for (addrp = ifaddr;
3434
35 (addrp != NULL &&
36 (strcmp(addrp->ifa_name, interface) != 0 ||
37 addrp->ifa_addr == NULL ||
38 addrp->ifa_addr->sa_family != AF_INET));
35 (addrp != NULL &&
36 (strcmp(addrp->ifa_name, interface) != 0 ||
37 addrp->ifa_addr == NULL ||
38 addrp->ifa_addr->sa_family != AF_INET));
3939
40 addrp = addrp->ifa_next) {
41 /* Check if the interface is down */
42 if (strcmp(addrp->ifa_name, interface) != 0)
43 continue;
44 found = true;
45 if ((addrp->ifa_flags & IFF_RUNNING) == 0) {
46 freeifaddrs(ifaddr);
47 return NULL;
48 }
40 addrp = addrp->ifa_next) {
41 /* Check if the interface is down */
42 if (strcmp(addrp->ifa_name, interface) != 0)
43 continue;
44 found = true;
45 if ((addrp->ifa_flags & IFF_RUNNING) == 0) {
46 freeifaddrs(ifaddr);
47 return NULL;
4948 }
49 }
5050
51 if (addrp == NULL) {
52 freeifaddrs(ifaddr);
53 return (found ? "no IP" : NULL);
54 }
51 if (addrp == NULL) {
52 freeifaddrs(ifaddr);
53 return (found ? "no IP" : NULL);
54 }
5555
56 int ret;
57 if ((ret = getnameinfo(addrp->ifa_addr, len, part, sizeof(part), NULL, 0, NI_NUMERICHOST)) != 0) {
58 fprintf(stderr, "i3status: getnameinfo(): %s\n", gai_strerror(ret));
59 freeifaddrs(ifaddr);
60 return "no IP";
61 }
56 int ret;
57 if ((ret = getnameinfo(addrp->ifa_addr, len, part, sizeof(part), NULL, 0, NI_NUMERICHOST)) != 0) {
58 fprintf(stderr, "i3status: getnameinfo(): %s\n", gai_strerror(ret));
59 freeifaddrs(ifaddr);
60 return "no IP";
61 }
6262
63 freeifaddrs(ifaddr);
64 return part;
63 freeifaddrs(ifaddr);
64 return part;
6565 }
66
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <sys/types.h>
22 #include <sys/socket.h>
33 #include <netinet/in.h>
1515 #include "i3status.h"
1616
1717 static char *get_sockname(struct addrinfo *addr) {
18 static char buf[INET6_ADDRSTRLEN+1];
19 struct sockaddr_storage local;
20 int ret;
21 int fd;
18 static char buf[INET6_ADDRSTRLEN + 1];
19 struct sockaddr_storage local;
20 int ret;
21 int fd;
2222
23 if ((fd = socket(addr->ai_family, SOCK_DGRAM, 0)) == -1) {
24 perror("socket()");
25 return NULL;
26 }
23 if ((fd = socket(addr->ai_family, SOCK_DGRAM, 0)) == -1) {
24 perror("socket()");
25 return NULL;
26 }
2727
28 /* Since the socket was created with SOCK_DGRAM, this is
29 * actually not establishing a connection or generating
30 * any other network traffic. Instead, as a side-effect,
31 * it saves the local address with which packets would
32 * be sent to the destination. */
33 if (connect(fd, addr->ai_addr, addr->ai_addrlen) == -1) {
34 /* We don’t display the error here because most
35 * likely, there just is no IPv6 connectivity.
36 * Thus, don’t spam the user’s console but just
37 * try the next address. */
38 (void)close(fd);
39 return NULL;
40 }
28 /* Since the socket was created with SOCK_DGRAM, this is
29 * actually not establishing a connection or generating
30 * any other network traffic. Instead, as a side-effect,
31 * it saves the local address with which packets would
32 * be sent to the destination. */
33 if (connect(fd, addr->ai_addr, addr->ai_addrlen) == -1) {
34 /* We don’t display the error here because most
35 * likely, there just is no IPv6 connectivity.
36 * Thus, don’t spam the user’s console but just
37 * try the next address. */
38 (void)close(fd);
39 return NULL;
40 }
4141
42 socklen_t local_len = sizeof(struct sockaddr_storage);
43 if (getsockname(fd, (struct sockaddr*)&local, &local_len) == -1) {
44 perror("getsockname()");
45 (void)close(fd);
46 return NULL;
47 }
42 socklen_t local_len = sizeof(struct sockaddr_storage);
43 if (getsockname(fd, (struct sockaddr *)&local, &local_len) == -1) {
44 perror("getsockname()");
45 (void)close(fd);
46 return NULL;
47 }
4848
49 memset(buf, 0, INET6_ADDRSTRLEN + 1);
50 if ((ret = getnameinfo((struct sockaddr*)&local, local_len,
51 buf, sizeof(buf), NULL, 0,
52 NI_NUMERICHOST)) != 0) {
53 fprintf(stderr, "i3status: getnameinfo(): %s\n", gai_strerror(ret));
54 (void)close(fd);
55 return NULL;
56 }
49 memset(buf, 0, INET6_ADDRSTRLEN + 1);
50 if ((ret = getnameinfo((struct sockaddr *)&local, local_len,
51 buf, sizeof(buf), NULL, 0,
52 NI_NUMERICHOST)) != 0) {
53 fprintf(stderr, "i3status: getnameinfo(): %s\n", gai_strerror(ret));
54 (void)close(fd);
55 return NULL;
56 }
5757
58 (void)close(fd);
59 return buf;
58 (void)close(fd);
59 return buf;
6060 }
6161
6262 /*
6464 * The char * is statically allocated and mustn't be freed
6565 */
6666 static char *get_ipv6_addr(void) {
67 struct addrinfo hints;
68 struct addrinfo *result, *resp;
69 static struct addrinfo *cached = NULL;
67 struct addrinfo hints;
68 struct addrinfo *result, *resp;
69 static struct addrinfo *cached = NULL;
7070
71 /* To save dns lookups (if they are not cached locally) and creating
72 * sockets, we save the fd and keep it open. */
73 if (cached != NULL)
74 return get_sockname(cached);
71 /* To save dns lookups (if they are not cached locally) and creating
72 * sockets, we save the fd and keep it open. */
73 if (cached != NULL)
74 return get_sockname(cached);
7575
76 memset(&hints, 0, sizeof(struct addrinfo));
77 hints.ai_family = AF_INET6;
78 hints.ai_socktype = SOCK_DGRAM;
76 memset(&hints, 0, sizeof(struct addrinfo));
77 hints.ai_family = AF_INET6;
78 hints.ai_socktype = SOCK_DGRAM;
7979
80 /* We use the public IPv6 of the K root server here. It doesn’t matter
81 * which IPv6 address we use (we don’t even send any packets), as long
82 * as it’s considered global by the kernel.
83 * NB: We don’t use a hostname since that would trigger a DNS lookup.
84 * By using an IPv6 address, getaddrinfo() will *not* do a DNS lookup,
85 * but return the address in the appropriate struct. */
86 if (getaddrinfo("2001:7fd::1", "domain", &hints, &result) != 0) {
87 /* We don’t display the error here because most
88 * likely, there just is no connectivity.
89 * Thus, don’t spam the user’s console. */
90 return NULL;
80 /* We use the public IPv6 of the K root server here. It doesn’t matter
81 * which IPv6 address we use (we don’t even send any packets), as long
82 * as it’s considered global by the kernel.
83 * NB: We don’t use a hostname since that would trigger a DNS lookup.
84 * By using an IPv6 address, getaddrinfo() will *not* do a DNS lookup,
85 * but return the address in the appropriate struct. */
86 if (getaddrinfo("2001:7fd::1", "domain", &hints, &result) != 0) {
87 /* We don’t display the error here because most
88 * likely, there just is no connectivity.
89 * Thus, don’t spam the user’s console. */
90 return NULL;
91 }
92
93 for (resp = result; resp != NULL; resp = resp->ai_next) {
94 char *addr_string = get_sockname(resp);
95 /* If we could not get our own address and there is more than
96 * one result for resolving k.root-servers.net, we cannot
97 * cache. Otherwise, no matter if we got IPv6 connectivity or
98 * not, we will cache the (single) result and are done. */
99 if (!addr_string && result->ai_next != NULL)
100 continue;
101
102 if ((cached = malloc(sizeof(struct addrinfo))) == NULL)
103 return NULL;
104 memcpy(cached, resp, sizeof(struct addrinfo));
105 if ((cached->ai_addr = malloc(resp->ai_addrlen)) == NULL) {
106 cached = NULL;
107 return NULL;
91108 }
109 memcpy(cached->ai_addr, resp->ai_addr, resp->ai_addrlen);
110 freeaddrinfo(result);
111 return addr_string;
112 }
92113
93 for (resp = result; resp != NULL; resp = resp->ai_next) {
94 char *addr_string = get_sockname(resp);
95 /* If we could not get our own address and there is more than
96 * one result for resolving k.root-servers.net, we cannot
97 * cache. Otherwise, no matter if we got IPv6 connectivity or
98 * not, we will cache the (single) result and are done. */
99 if (!addr_string && result->ai_next != NULL)
100 continue;
101
102 if ((cached = malloc(sizeof(struct addrinfo))) == NULL)
103 return NULL;
104 memcpy(cached, resp, sizeof(struct addrinfo));
105 if ((cached->ai_addr = malloc(resp->ai_addrlen)) == NULL) {
106 cached = NULL;
107 return NULL;
108 }
109 memcpy(cached->ai_addr, resp->ai_addr, resp->ai_addrlen);
110 freeaddrinfo(result);
111 return addr_string;
112 }
113
114 freeaddrinfo(result);
115 return NULL;
114 freeaddrinfo(result);
115 return NULL;
116116 }
117117
118118 void print_ipv6_info(yajl_gen json_gen, char *buffer, const char *format_up, const char *format_down) {
119 const char *walk;
120 char *addr_string = get_ipv6_addr();
121 char *outwalk = buffer;
119 const char *walk;
120 char *addr_string = get_ipv6_addr();
121 char *outwalk = buffer;
122122
123 if (addr_string == NULL) {
124 START_COLOR("color_bad");
125 outwalk += sprintf(outwalk, "%s", format_down);
126 END_COLOR;
127 OUTPUT_FULL_TEXT(buffer);
128 return;
123 if (addr_string == NULL) {
124 START_COLOR("color_bad");
125 outwalk += sprintf(outwalk, "%s", format_down);
126 END_COLOR;
127 OUTPUT_FULL_TEXT(buffer);
128 return;
129 }
130
131 START_COLOR("color_good");
132 for (walk = format_up; *walk != '\0'; walk++) {
133 if (*walk != '%') {
134 *(outwalk++) = *walk;
135 continue;
129136 }
130137
131 START_COLOR("color_good");
132 for (walk = format_up; *walk != '\0'; walk++) {
133 if (*walk != '%') {
134 *(outwalk++) = *walk;
135 continue;
136 }
137
138 if (strncmp(walk+1, "ip", strlen("ip")) == 0) {
139 outwalk += sprintf(outwalk, "%s", addr_string);
140 walk += strlen("ip");
141 }
138 if (BEGINS_WITH(walk + 1, "ip")) {
139 outwalk += sprintf(outwalk, "%s", addr_string);
140 walk += strlen("ip");
142141 }
143 END_COLOR;
144 OUTPUT_FULL_TEXT(buffer);
142 }
143 END_COLOR;
144 OUTPUT_FULL_TEXT(buffer);
145145 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include "i3status.h"
22 #include <stdlib.h>
33 #include <stdio.h>
66 #include <yajl/yajl_version.h>
77
88 void print_load(yajl_gen json_gen, char *buffer, const char *format, const float max_threshold) {
9 char *outwalk = buffer;
10 /* Get load */
9 char *outwalk = buffer;
10 /* Get load */
1111
1212 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(linux) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(sun) || defined(__DragonFly__)
13 double loadavg[3];
14 const char *walk;
15 bool colorful_output = false;
13 double loadavg[3];
14 const char *walk;
15 bool colorful_output = false;
1616
17 if (getloadavg(loadavg, 3) == -1)
18 goto error;
17 if (getloadavg(loadavg, 3) == -1)
18 goto error;
1919
20 for (walk = format; *walk != '\0'; walk++) {
21 if (*walk != '%') {
22 *(outwalk++) = *walk;
23 continue;
24 }
25 if (loadavg[0] >= max_threshold) {
26 START_COLOR("color_bad");
27 colorful_output = true;
28 }
29
30 if (BEGINS_WITH(walk+1, "1min")) {
31 outwalk += sprintf(outwalk, "%1.2f", loadavg[0]);
32 walk += strlen("1min");
33 }
34
35 if (BEGINS_WITH(walk+1, "5min")) {
36 outwalk += sprintf(outwalk, "%1.2f", loadavg[1]);
37 walk += strlen("5min");
38 }
39
40 if (BEGINS_WITH(walk+1, "15min")) {
41 outwalk += sprintf(outwalk, "%1.2f", loadavg[2]);
42 walk += strlen("15min");
43 }
44 if (colorful_output)
45 END_COLOR;
20 for (walk = format; *walk != '\0'; walk++) {
21 if (*walk != '%') {
22 *(outwalk++) = *walk;
23 continue;
24 }
25 if (loadavg[0] >= max_threshold) {
26 START_COLOR("color_bad");
27 colorful_output = true;
4628 }
4729
48 *outwalk = '\0';
49 OUTPUT_FULL_TEXT(buffer);
30 if (BEGINS_WITH(walk + 1, "1min")) {
31 outwalk += sprintf(outwalk, "%1.2f", loadavg[0]);
32 walk += strlen("1min");
33 }
5034
51 return;
35 if (BEGINS_WITH(walk + 1, "5min")) {
36 outwalk += sprintf(outwalk, "%1.2f", loadavg[1]);
37 walk += strlen("5min");
38 }
39
40 if (BEGINS_WITH(walk + 1, "15min")) {
41 outwalk += sprintf(outwalk, "%1.2f", loadavg[2]);
42 walk += strlen("15min");
43 }
44 if (colorful_output)
45 END_COLOR;
46 }
47
48 *outwalk = '\0';
49 OUTPUT_FULL_TEXT(buffer);
50
51 return;
5252 error:
5353 #endif
54 OUTPUT_FULL_TEXT("cant read load");
55 (void)fputs("i3status: Cannot read system load using getloadavg()\n", stderr);
54 OUTPUT_FULL_TEXT("cant read load");
55 (void)fputs("i3status: Cannot read system load using getloadavg()\n", stderr);
5656 }
0 // vim:ts=4:sw=4:expandtab
01 #include <stdio.h>
12 #include <string.h>
23 #include <yajl/yajl_gen.h>
56 #include "i3status.h"
67
78 void print_path_exists(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format) {
8 const char *walk;
9 char *outwalk = buffer;
10 struct stat st;
11 const bool exists = (stat(path, &st) == 0);
9 const char *walk;
10 char *outwalk = buffer;
11 struct stat st;
12 const bool exists = (stat(path, &st) == 0);
1213
13 INSTANCE(path);
14 INSTANCE(path);
1415
15 START_COLOR((exists ? "color_good" : "color_bad"));
16 START_COLOR((exists ? "color_good" : "color_bad"));
1617
17 for (walk = format; *walk != '\0'; walk++) {
18 if (*walk != '%') {
19 *(outwalk++) = *walk;
20 continue;
21 }
22
23 if (strncmp(walk+1, "title", strlen("title")) == 0) {
24 outwalk += sprintf(outwalk, "%s", title);
25 walk += strlen("title");
26 } else if (strncmp(walk+1, "status", strlen("status")) == 0) {
27 outwalk += sprintf(outwalk, "%s", (exists ? "yes" : "no"));
28 walk += strlen("status");
29 }
18 for (walk = format; *walk != '\0'; walk++) {
19 if (*walk != '%') {
20 *(outwalk++) = *walk;
21 continue;
3022 }
3123
32 END_COLOR;
33 OUTPUT_FULL_TEXT(buffer);
24 if (BEGINS_WITH(walk + 1, "title")) {
25 outwalk += sprintf(outwalk, "%s", title);
26 walk += strlen("title");
27 } else if (BEGINS_WITH(walk + 1, "status")) {
28 outwalk += sprintf(outwalk, "%s", (exists ? "yes" : "no"));
29 walk += strlen("status");
30 }
31 }
32
33 END_COLOR;
34 OUTPUT_FULL_TEXT(buffer);
3435 }
0 // vim:ts=4:sw=4:expandtab
01 #include <stdio.h>
12 #include <string.h>
23 #include <yajl/yajl_gen.h>
45 #include "i3status.h"
56
67 void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format) {
7 bool running = process_runs(pidfile);
8 const char *walk;
9 char *outwalk = buffer;
8 bool running = process_runs(pidfile);
9 const char *walk;
10 char *outwalk = buffer;
1011
11 INSTANCE(pidfile);
12 INSTANCE(pidfile);
1213
13 START_COLOR((running ? "color_good" : "color_bad"));
14 START_COLOR((running ? "color_good" : "color_bad"));
1415
15 for (walk = format; *walk != '\0'; walk++) {
16 if (*walk != '%') {
17 *(outwalk++) = *walk;
18 continue;
19 }
20
21 if (strncmp(walk+1, "title", strlen("title")) == 0) {
22 outwalk += sprintf(outwalk, "%s", title);
23 walk += strlen("title");
24 } else if (strncmp(walk+1, "status", strlen("status")) == 0) {
25 outwalk += sprintf(outwalk, "%s", (running ? "yes" : "no"));
26 walk += strlen("status");
27 }
16 for (walk = format; *walk != '\0'; walk++) {
17 if (*walk != '%') {
18 *(outwalk++) = *walk;
19 continue;
2820 }
2921
30 END_COLOR;
31 OUTPUT_FULL_TEXT(buffer);
22 if (BEGINS_WITH(walk + 1, "title")) {
23 outwalk += sprintf(outwalk, "%s", title);
24 walk += strlen("title");
25 } else if (BEGINS_WITH(walk + 1, "status")) {
26 outwalk += sprintf(outwalk, "%s", (running ? "yes" : "no"));
27 walk += strlen("status");
28 }
29 }
30
31 END_COLOR;
32 OUTPUT_FULL_TEXT(buffer);
3233 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <time.h>
22 #include <stdio.h>
33 #include <stdlib.h>
1212 static const char *current_timezone = NULL;
1313
1414 void set_timezone(const char *tz) {
15 if (!local_timezone_init) {
16 /* First call, initialize. */
17 local_timezone = getenv("TZ");
18 local_timezone_init = true;
15 if (!local_timezone_init) {
16 /* First call, initialize. */
17 local_timezone = getenv("TZ");
18 local_timezone_init = true;
19 }
20 if (tz == NULL || tz[0] == '\0') {
21 /* User wants localtime. */
22 tz = local_timezone;
23 }
24 if (tz != current_timezone) {
25 if (tz) {
26 setenv("TZ", tz, 1);
27 } else {
28 unsetenv("TZ");
1929 }
20 if (tz == NULL || tz[0] == '\0') {
21 /* User wants localtime. */
22 tz = local_timezone;
23 }
24 if (tz != current_timezone) {
25 if (tz) {
26 setenv("TZ", tz, 1);
27 } else {
28 unsetenv("TZ");
29 }
30 tzset();
31 current_timezone = tz;
32 }
30 tzset();
31 current_timezone = tz;
32 }
3333 }
3434
3535 void print_time(yajl_gen json_gen, char *buffer, const char *format, const char *tz, time_t t) {
36 char *outwalk = buffer;
37 struct tm tm;
36 char *outwalk = buffer;
37 struct tm tm;
3838
39 /* Convert time and format output. */
40 set_timezone(tz);
41 localtime_r(&t, &tm);
42 outwalk += strftime(outwalk, 4095, format, &tm);
43 *outwalk = '\0';
44 OUTPUT_FULL_TEXT(buffer);
39 /* Convert time and format output. */
40 set_timezone(tz);
41 localtime_r(&t, &tm);
42 outwalk += strftime(outwalk, 4095, format, &tm);
43 *outwalk = '\0';
44 OUTPUT_FULL_TEXT(buffer);
4545 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <time.h>
22 #include <string.h>
33 #include <stdlib.h>
2626 #include "queue.h"
2727
2828 void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_muted, const char *device, const char *mixer, int mixer_idx) {
29 char *outwalk = buffer;
30 int pbval = 1;
29 char *outwalk = buffer;
30 int pbval = 1;
3131
32 /* Printing volume only works with ALSA at the moment */
33 if (output_format == O_I3BAR) {
34 char *instance;
35 asprintf(&instance, "%s.%s.%d", device, mixer, mixer_idx);
36 INSTANCE(instance);
37 free(instance);
32 /* Printing volume only works with ALSA at the moment */
33 if (output_format == O_I3BAR) {
34 char *instance;
35 asprintf(&instance, "%s.%s.%d", device, mixer, mixer_idx);
36 INSTANCE(instance);
37 free(instance);
38 }
39 #ifdef LINUX
40 int err;
41 snd_mixer_t *m;
42 snd_mixer_selem_id_t *sid;
43 snd_mixer_elem_t *elem;
44 long min, max, val;
45 int avg;
46
47 if ((err = snd_mixer_open(&m, 0)) < 0) {
48 fprintf(stderr, "i3status: ALSA: Cannot open mixer: %s\n", snd_strerror(err));
49 goto out;
50 }
51
52 /* Attach this mixer handle to the given device */
53 if ((err = snd_mixer_attach(m, device)) < 0) {
54 fprintf(stderr, "i3status: ALSA: Cannot attach mixer to device: %s\n", snd_strerror(err));
55 snd_mixer_close(m);
56 goto out;
57 }
58
59 /* Register this mixer */
60 if ((err = snd_mixer_selem_register(m, NULL, NULL)) < 0) {
61 fprintf(stderr, "i3status: ALSA: snd_mixer_selem_register: %s\n", snd_strerror(err));
62 snd_mixer_close(m);
63 goto out;
64 }
65
66 if ((err = snd_mixer_load(m)) < 0) {
67 fprintf(stderr, "i3status: ALSA: snd_mixer_load: %s\n", snd_strerror(err));
68 snd_mixer_close(m);
69 goto out;
70 }
71
72 snd_mixer_selem_id_malloc(&sid);
73 if (sid == NULL) {
74 snd_mixer_close(m);
75 goto out;
76 }
77
78 /* Find the given mixer */
79 snd_mixer_selem_id_set_index(sid, mixer_idx);
80 snd_mixer_selem_id_set_name(sid, mixer);
81 if (!(elem = snd_mixer_find_selem(m, sid))) {
82 fprintf(stderr, "i3status: ALSA: Cannot find mixer %s (index %i)\n",
83 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
84 snd_mixer_close(m);
85 snd_mixer_selem_id_free(sid);
86 goto out;
87 }
88
89 /* Get the volume range to convert the volume later */
90 snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
91
92 snd_mixer_handle_events(m);
93 snd_mixer_selem_get_playback_volume(elem, 0, &val);
94 if (max != 100) {
95 float avgf = ((float)val / max) * 100;
96 avg = (int)avgf;
97 avg = (avgf - avg < 0.5 ? avg : (avg + 1));
98 } else
99 avg = (int)val;
100
101 /* Check for mute */
102 if (snd_mixer_selem_has_playback_switch(elem)) {
103 if ((err = snd_mixer_selem_get_playback_switch(elem, 0, &pbval)) < 0)
104 fprintf(stderr, "i3status: ALSA: playback_switch: %s\n", snd_strerror(err));
105 if (!pbval) {
106 START_COLOR("color_degraded");
107 fmt = fmt_muted;
38108 }
39 #ifdef LINUX
40 int err;
41 snd_mixer_t *m;
42 snd_mixer_selem_id_t *sid;
43 snd_mixer_elem_t *elem;
44 long min, max, val;
45 int avg;
109 }
46110
47 if ((err = snd_mixer_open(&m, 0)) < 0) {
48 fprintf(stderr, "i3status: ALSA: Cannot open mixer: %s\n", snd_strerror(err));
49 goto out;
50 }
111 snd_mixer_close(m);
112 snd_mixer_selem_id_free(sid);
51113
52 /* Attach this mixer handle to the given device */
53 if ((err = snd_mixer_attach(m, device)) < 0) {
54 fprintf(stderr, "i3status: ALSA: Cannot attach mixer to device: %s\n", snd_strerror(err));
55 snd_mixer_close(m);
56 goto out;
57 }
58
59 /* Register this mixer */
60 if ((err = snd_mixer_selem_register(m, NULL, NULL)) < 0) {
61 fprintf(stderr, "i3status: ALSA: snd_mixer_selem_register: %s\n", snd_strerror(err));
62 snd_mixer_close(m);
63 goto out;
64 }
65
66 if ((err = snd_mixer_load(m)) < 0) {
67 fprintf(stderr, "i3status: ALSA: snd_mixer_load: %s\n", snd_strerror(err));
68 snd_mixer_close(m);
69 goto out;
70 }
71
72 snd_mixer_selem_id_malloc(&sid);
73 if (sid == NULL) {
74 snd_mixer_close(m);
75 goto out;
76 }
77
78 /* Find the given mixer */
79 snd_mixer_selem_id_set_index(sid, mixer_idx);
80 snd_mixer_selem_id_set_name(sid, mixer);
81 if (!(elem = snd_mixer_find_selem(m, sid))) {
82 fprintf(stderr, "i3status: ALSA: Cannot find mixer %s (index %i)\n",
83 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
84 snd_mixer_close(m);
85 snd_mixer_selem_id_free(sid);
86 goto out;
87 }
88
89 /* Get the volume range to convert the volume later */
90 snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
91
92 snd_mixer_handle_events (m);
93 snd_mixer_selem_get_playback_volume (elem, 0, &val);
94 if (max != 100) {
95 float avgf = ((float)val / max) * 100;
96 avg = (int)avgf;
97 avg = (avgf - avg < 0.5 ? avg : (avg+1));
98 } else avg = (int)val;
99
100 /* Check for mute */
101 if (snd_mixer_selem_has_playback_switch(elem)) {
102 if ((err = snd_mixer_selem_get_playback_switch(elem, 0, &pbval)) < 0)
103 fprintf (stderr, "i3status: ALSA: playback_switch: %s\n", snd_strerror(err));
104 if (!pbval) {
105 START_COLOR("color_degraded");
106 fmt = fmt_muted;
107 }
108 }
109
110 snd_mixer_close(m);
111 snd_mixer_selem_id_free(sid);
112
113 const char *walk = fmt;
114 for (; *walk != '\0'; walk++) {
115 if (*walk != '%') {
116 *(outwalk++) = *walk;
117 continue;
118 }
119 if (BEGINS_WITH(walk+1, "%")) {
120 outwalk += sprintf(outwalk, "%%");
121 walk += strlen("%");
122 }
123 if (BEGINS_WITH(walk+1, "volume")) {
124 outwalk += sprintf(outwalk, "%d%%", avg);
125 walk += strlen("volume");
126 }
127 }
114 const char *walk = fmt;
115 for (; *walk != '\0'; walk++) {
116 if (*walk != '%') {
117 *(outwalk++) = *walk;
118 continue;
119 }
120 if (BEGINS_WITH(walk + 1, "%")) {
121 outwalk += sprintf(outwalk, "%%");
122 walk += strlen("%");
123 }
124 if (BEGINS_WITH(walk + 1, "volume")) {
125 outwalk += sprintf(outwalk, "%d%%", avg);
126 walk += strlen("volume");
127 }
128 }
128129 #endif
129130 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
130 char *mixerpath;
131 char defaultmixer[] = "/dev/mixer";
132 int mixfd, vol, devmask = 0;
133 pbval = 1;
131 char *mixerpath;
132 char defaultmixer[] = "/dev/mixer";
133 int mixfd, vol, devmask = 0;
134 pbval = 1;
134135
135 if (mixer_idx > 0)
136 asprintf(&mixerpath, "/dev/mixer%d", mixer_idx);
137 else
138 mixerpath = defaultmixer;
136 if (mixer_idx > 0)
137 asprintf(&mixerpath, "/dev/mixer%d", mixer_idx);
138 else
139 mixerpath = defaultmixer;
139140
140 if ((mixfd = open(mixerpath, O_RDWR)) < 0)
141 return;
141 if ((mixfd = open(mixerpath, O_RDWR)) < 0)
142 return;
142143
143 if (mixer_idx > 0)
144 free(mixerpath);
144 if (mixer_idx > 0)
145 free(mixerpath);
145146
146 if (ioctl(mixfd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
147 return;
148 if (ioctl(mixfd, MIXER_READ(0),&vol) == -1)
149 return;
147 if (ioctl(mixfd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
148 return;
149 if (ioctl(mixfd, MIXER_READ(0), &vol) == -1)
150 return;
150151
151 if (((vol & 0x7f) == 0) && (((vol >> 8) & 0x7f) == 0)) {
152 START_COLOR("color_degraded");
153 pbval = 0;
152 if (((vol & 0x7f) == 0) && (((vol >> 8) & 0x7f) == 0)) {
153 START_COLOR("color_degraded");
154 pbval = 0;
155 }
156
157 const char *walk = fmt;
158 for (; *walk != '\0'; walk++) {
159 if (*walk != '%') {
160 *(outwalk++) = *walk;
161 continue;
154162 }
155
156 const char *walk = fmt;
157 for (; *walk != '\0'; walk++) {
158 if (*walk != '%') {
159 *(outwalk++) = *walk;
160 continue;
161 }
162 if (BEGINS_WITH(walk+1, "%")) {
163 outwalk += sprintf(outwalk, "%%");
164 walk += strlen("%");
165 }
166 if (BEGINS_WITH(walk+1, "volume")) {
167 outwalk += sprintf(outwalk, "%d%%", vol & 0x7f);
168 walk += strlen("volume");
169 }
163 if (BEGINS_WITH(walk + 1, "%")) {
164 outwalk += sprintf(outwalk, "%%");
165 walk += strlen("%");
170166 }
171 close(mixfd);
167 if (BEGINS_WITH(walk + 1, "volume")) {
168 outwalk += sprintf(outwalk, "%d%%", vol & 0x7f);
169 walk += strlen("volume");
170 }
171 }
172 close(mixfd);
172173 #endif
173174
174175 out:
175 *outwalk = '\0';
176 OUTPUT_FULL_TEXT(buffer);
177
178 if (!pbval)
179 END_COLOR;
176 *outwalk = '\0';
177 if (!pbval)
178 END_COLOR;
179 OUTPUT_FULL_TEXT(buffer);
180180 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <stdio.h>
22 #include <string.h>
33 #include <yajl/yajl_gen.h>
5050
5151 #include "i3status.h"
5252
53 #define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0)
54 #define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1)
55 #define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2)
56 #define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3)
53 #define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0)
54 #define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1)
55 #define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2)
56 #define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3)
57 #define WIRELESS_INFO_FLAG_HAS_FREQUENCY (1 << 4)
5758
5859 #define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f))
5960
6061 typedef struct {
61 int flags;
62 char essid[IW_ESSID_MAX_SIZE + 1];
63 int quality;
64 int quality_max;
65 int quality_average;
66 int signal_level;
67 int signal_level_max;
68 int noise_level;
69 int noise_level_max;
70 int bitrate;
62 int flags;
63 char essid[IW_ESSID_MAX_SIZE + 1];
64 int quality;
65 int quality_max;
66 int quality_average;
67 int signal_level;
68 int signal_level_max;
69 int noise_level;
70 int noise_level_max;
71 int bitrate;
72 double frequency;
7173 } wireless_info_t;
7274
7375 static int get_wireless_info(const char *interface, wireless_info_t *info) {
74 memset(info, 0, sizeof(wireless_info_t));
76 memset(info, 0, sizeof(wireless_info_t));
7577
7678 #ifdef LINUX
77 int skfd = iw_sockets_open();
78 if (skfd < 0) {
79 perror("iw_sockets_open");
80 return 0;
81 }
82
83 wireless_config wcfg;
84 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
85 close(skfd);
86 return 0;
87 }
88
89 if (wcfg.has_essid && wcfg.essid_on) {
90 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
91 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
92 info->essid[IW_ESSID_MAX_SIZE] = '\0';
93 }
94
95 /* If the function iw_get_stats does not return proper stats, the
96 wifi is considered as down.
97 Since ad-hoc network does not have theses stats, we need to return
98 here for this mode. */
99 if (wcfg.mode == 1) {
100 close(skfd);
101 return 1;
102 }
103
104 /* Wireless quality is a relative value in a driver-specific range.
105 Signal and noise level can be either relative or absolute values
106 in dBm. Furthermore, noise and quality can be expressed directly
107 in dBm or in RCPI (802.11k), which we convert to dBm. When those
108 values are expressed directly in dBm, they range from -192 to 63,
109 and since the values are packed into 8 bits, we need to perform
110 8-bit arithmetic on them. Assume absolute values if everything
111 else fails (driver bug). */
112
113 iwrange range;
114 if (iw_get_range_info(skfd, interface, &range) < 0) {
115 close(skfd);
116 return 0;
117 }
118
119 iwstats stats;
120 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
121 close(skfd);
122 return 0;
123 }
124
125 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
126 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
127 info->quality = stats.qual.qual;
128 info->quality_max = range.max_qual.qual;
129 info->quality_average = range.avg_qual.qual;
130 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
131 }
132
133 if (stats.qual.updated & IW_QUAL_RCPI) {
134 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
135 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
136 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
137 }
138 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
139 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
140 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
141 }
142 }
143 else {
144 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
145 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
146 info->signal_level = stats.qual.level;
147 if (info->signal_level > 63)
148 info->signal_level -= 256;
149 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
150 }
151 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
152 info->noise_level = stats.qual.noise;
153 if (info->noise_level > 63)
154 info->noise_level -= 256;
155 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
156 }
157 }
158 else {
159 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
160 info->signal_level = stats.qual.level;
161 info->signal_level_max = range.max_qual.level;
162 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
163 }
164 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
165 info->noise_level = stats.qual.noise;
166 info->noise_level_max = range.max_qual.noise;
167 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
168 }
169 }
170 }
171 }
172 else {
173 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
174 info->quality = stats.qual.qual;
175 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
176 }
79 int skfd = iw_sockets_open();
80 if (skfd < 0) {
81 perror("iw_sockets_open");
82 return 0;
83 }
84
85 wireless_config wcfg;
86 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
87 close(skfd);
88 return 0;
89 }
90
91 if (wcfg.has_essid && wcfg.essid_on) {
92 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
93 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
94 info->essid[IW_ESSID_MAX_SIZE] = '\0';
95 }
96
97 if (wcfg.has_freq) {
98 info->frequency = wcfg.freq;
99 info->flags |= WIRELESS_INFO_FLAG_HAS_FREQUENCY;
100 }
101
102 /* If the function iw_get_stats does not return proper stats, the
103 * wifi is considered as down.
104 * Since ad-hoc network does not have theses stats, we need to return
105 * here for this mode. */
106 if (wcfg.mode == 1) {
107 close(skfd);
108 return 1;
109 }
110
111 /* Wireless quality is a relative value in a driver-specific range.
112 * Signal and noise level can be either relative or absolute values
113 * in dBm. Furthermore, noise and quality can be expressed directly
114 * in dBm or in RCPI (802.11k), which we convert to dBm. When those
115 * values are expressed directly in dBm, they range from -192 to 63,
116 * and since the values are packed into 8 bits, we need to perform
117 * 8-bit arithmetic on them. Assume absolute values if everything
118 * else fails (driver bug). */
119
120 iwrange range;
121 if (iw_get_range_info(skfd, interface, &range) < 0) {
122 close(skfd);
123 return 0;
124 }
125
126 iwstats stats;
127 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
128 close(skfd);
129 return 0;
130 }
131
132 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
133 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
134 info->quality = stats.qual.qual;
135 info->quality_max = range.max_qual.qual;
136 info->quality_average = range.avg_qual.qual;
137 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
138 }
139
140 if (stats.qual.updated & IW_QUAL_RCPI) {
141 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
142 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
143 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
144 }
145 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
146 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
147 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
148 }
149 } else {
150 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
177151 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
178 info->quality = stats.qual.level;
179 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
152 info->signal_level = stats.qual.level;
153 if (info->signal_level > 63)
154 info->signal_level -= 256;
155 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
180156 }
181157 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
182 info->quality = stats.qual.noise;
183 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
158 info->noise_level = stats.qual.noise;
159 if (info->noise_level > 63)
160 info->noise_level -= 256;
161 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
184162 }
185 }
186
187 struct iwreq wrq;
188 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
189 info->bitrate = wrq.u.bitrate.value;
190
191 close(skfd);
192 return 1;
163 } else {
164 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
165 info->signal_level = stats.qual.level;
166 info->signal_level_max = range.max_qual.level;
167 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
168 }
169 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
170 info->noise_level = stats.qual.noise;
171 info->noise_level_max = range.max_qual.noise;
172 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
173 }
174 }
175 }
176 } else {
177 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
178 info->quality = stats.qual.qual;
179 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
180 }
181 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
182 info->quality = stats.qual.level;
183 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
184 }
185 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
186 info->quality = stats.qual.noise;
187 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
188 }
189 }
190
191 struct iwreq wrq;
192 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
193 info->bitrate = wrq.u.bitrate.value;
194
195 close(skfd);
196 return 1;
193197 #endif
194198 #if defined(__FreeBSD__) || defined(__DragonFly__)
195 int s, len, inwid;
196 uint8_t buf[24 * 1024], *cp;
197 struct ieee80211req na;
198 char network_id[IEEE80211_NWID_LEN + 1];
199
200 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
201 return (0);
202
203 memset(&na, 0, sizeof(na));
204 strlcpy(na.i_name, interface, sizeof(na.i_name));
205 na.i_type = IEEE80211_IOC_SSID;
206 na.i_data = &info->essid[0];
207 na.i_len = IEEE80211_NWID_LEN + 1;
208 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
209 close(s);
210 return (0);
211 }
212 if (inwid == 0) {
213 if (na.i_len <= IEEE80211_NWID_LEN)
214 len = na.i_len + 1;
199 int s, len, inwid;
200 uint8_t buf[24 * 1024], *cp;
201 struct ieee80211req na;
202 char network_id[IEEE80211_NWID_LEN + 1];
203
204 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
205 return (0);
206
207 memset(&na, 0, sizeof(na));
208 strlcpy(na.i_name, interface, sizeof(na.i_name));
209 na.i_type = IEEE80211_IOC_SSID;
210 na.i_data = &info->essid[0];
211 na.i_len = IEEE80211_NWID_LEN + 1;
212 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
213 close(s);
214 return (0);
215 }
216 if (inwid == 0) {
217 if (na.i_len <= IEEE80211_NWID_LEN)
218 len = na.i_len + 1;
219 else
220 len = IEEE80211_NWID_LEN + 1;
221 info->essid[len - 1] = '\0';
222 } else {
223 close(s);
224 return (0);
225 }
226 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
227
228 memset(&na, 0, sizeof(na));
229 strlcpy(na.i_name, interface, sizeof(na.i_name));
230 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
231 na.i_data = buf;
232 na.i_len = sizeof(buf);
233
234 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
235 printf("fail\n");
236 close(s);
237 return (0);
238 }
239
240 close(s);
241 len = na.i_len;
242 cp = buf;
243 struct ieee80211req_scan_result *sr;
244 uint8_t *vp;
245 sr = (struct ieee80211req_scan_result *)cp;
246 vp = (u_int8_t *)(sr + 1);
247 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
248 if (!strcmp(network_id, &info->essid[0])) {
249 info->signal_level = sr->isr_rssi;
250 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
251 info->noise_level = sr->isr_noise;
252 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
253 info->quality = sr->isr_intval;
254 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
255 }
256
257 return 1;
258 #endif
259 #ifdef __OpenBSD__
260 struct ifreq ifr;
261 struct ieee80211_bssid bssid;
262 struct ieee80211_nwid nwid;
263 struct ieee80211_nodereq nr;
264
265 struct ether_addr ea;
266
267 int s, len, ibssid, inwid;
268 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
269
270 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
271 return (0);
272
273 memset(&ifr, 0, sizeof(ifr));
274 ifr.ifr_data = (caddr_t)&nwid;
275 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
276 inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
277
278 memset(&bssid, 0, sizeof(bssid));
279 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
280 ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
281
282 if (ibssid != 0 || inwid != 0) {
283 close(s);
284 return 0;
285 }
286
287 /* NWID */
288 {
289 if (nwid.i_len <= IEEE80211_NWID_LEN)
290 len = nwid.i_len + 1;
291 else
292 len = IEEE80211_NWID_LEN + 1;
293
294 strncpy(&info->essid[0], nwid.i_nwid, len);
295 info->essid[IW_ESSID_MAX_SIZE] = '\0';
296 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
297 }
298
299 /* Signal strength */
300 {
301 memset(&zero_bssid, 0, sizeof(zero_bssid));
302 if (ibssid == 0 && memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
303 memcpy(&ea.ether_addr_octet, bssid.i_bssid, sizeof(ea.ether_addr_octet));
304
305 bzero(&nr, sizeof(nr));
306 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
307 strlcpy(nr.nr_ifname, interface, sizeof(nr.nr_ifname));
308
309 if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
310 if (nr.nr_max_rssi)
311 info->signal_level_max = IEEE80211_NODEREQ_RSSI(&nr);
215312 else
216 len = IEEE80211_NWID_LEN + 1;
217 info->essid[len -1] = '\0';
218 } else {
219 close(s);
220 return (0);
221 }
222 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
223
224 memset(&na, 0, sizeof(na));
225 strlcpy(na.i_name, interface, sizeof(na.i_name));
226 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
227 na.i_data = buf;
228 na.i_len = sizeof(buf);
229
230 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
231 printf("fail\n");
232 close(s);
233 return (0);
234 }
235
236 close(s);
237 len = na.i_len;
238 cp = buf;
239 struct ieee80211req_scan_result *sr;
240 uint8_t *vp;
241 sr = (struct ieee80211req_scan_result *)cp;
242 vp = (u_int8_t *)(sr + 1);
243 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
244 if (!strcmp(network_id, &info->essid[0])) {
245 info->signal_level = sr->isr_rssi;
313 info->signal_level = nr.nr_rssi;
314
246315 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
247 info->noise_level = sr->isr_noise;
248 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
249 info->quality = sr->isr_intval;
250 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
251 }
252
253 return 1;
254 #endif
255 #ifdef __OpenBSD__
256 struct ifreq ifr;
257 struct ieee80211_bssid bssid;
258 struct ieee80211_nwid nwid;
259 struct ieee80211_nodereq nr;
260
261 struct ether_addr ea;
262
263 int s, len, ibssid, inwid;
264 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
265
266 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
267 return (0);
268
269 memset(&ifr, 0, sizeof(ifr));
270 ifr.ifr_data = (caddr_t)&nwid;
271 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
272 inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
273
274 memset(&bssid, 0, sizeof(bssid));
275 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
276 ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
277
278 if (ibssid != 0 || inwid != 0) {
279 close(s);
280 return 0;
281 }
282
283 /* NWID */
284 {
285 if (nwid.i_len <= IEEE80211_NWID_LEN)
286 len = nwid.i_len + 1;
287 else
288 len = IEEE80211_NWID_LEN + 1;
289
290 strncpy(&info->essid[0], nwid.i_nwid, len);
291 info->essid[IW_ESSID_MAX_SIZE] = '\0';
292 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
293 }
294
295 /* Signal strength */
296 {
297 memset(&zero_bssid, 0, sizeof(zero_bssid));
298 if (ibssid == 0 && memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
299 memcpy(&ea.ether_addr_octet, bssid.i_bssid, sizeof(ea.ether_addr_octet));
300
301 bzero(&nr, sizeof(nr));
302 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
303 strlcpy(nr.nr_ifname, interface, sizeof(nr.nr_ifname));
304
305 if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
306 if (nr.nr_max_rssi)
307 info->signal_level_max = IEEE80211_NODEREQ_RSSI(&nr);
308 else
309 info->signal_level = nr.nr_rssi;
310
311 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
312 }
313 }
314 }
315
316 close(s);
317 return 1;
318 #endif
319 return 0;
316 }
317 }
318 }
319
320 close(s);
321 return 1;
322 #endif
323 return 0;
320324 }
321325
322326 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
323 const char *walk;
324 char *outwalk = buffer;
325 wireless_info_t info;
326
327 INSTANCE(interface);
328
329 const char *ip_address = get_ip_addr(interface);
330 if (ip_address == NULL) {
331 START_COLOR("color_bad");
332 outwalk += sprintf(outwalk, "%s", format_down);
333 goto out;
334 }
335
336 if (get_wireless_info(interface, &info)) {
337 walk = format_up;
338 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
339 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
327 const char *walk;
328 char *outwalk = buffer;
329 wireless_info_t info;
330
331 INSTANCE(interface);
332
333 const char *ip_address = get_ip_addr(interface);
334 if (ip_address == NULL) {
335 START_COLOR("color_bad");
336 outwalk += sprintf(outwalk, "%s", format_down);
337 goto out;
338 }
339
340 if (get_wireless_info(interface, &info)) {
341 walk = format_up;
342 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
343 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
344 else
345 START_COLOR("color_good");
346 } else {
347 walk = format_down;
348 START_COLOR("color_bad");
349 }
350
351 for (; *walk != '\0'; walk++) {
352 if (*walk != '%') {
353 *(outwalk++) = *walk;
354 continue;
355 }
356
357 if (BEGINS_WITH(walk + 1, "quality")) {
358 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
359 if (info.quality_max)
360 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
340361 else
341 START_COLOR("color_good");
342 } else {
343 walk = format_down;
344 START_COLOR("color_bad");
345 }
346
347 for (; *walk != '\0'; walk++) {
348 if (*walk != '%') {
349 *(outwalk++) = *walk;
350 continue;
351 }
352
353 if (BEGINS_WITH(walk+1, "quality")) {
354 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
355 if (info.quality_max)
356 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
357 else
358 outwalk += sprintf(outwalk, "%d", info.quality);
359 } else {
360 *(outwalk++) = '?';
361 }
362 walk += strlen("quality");
363 }
364
365 if (BEGINS_WITH(walk+1, "signal")) {
366 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
367 if (info.signal_level_max)
368 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
369 else
370 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
371 } else {
372 *(outwalk++) = '?';
373 }
374 walk += strlen("signal");
375 }
376
377 if (BEGINS_WITH(walk+1, "noise")) {
378 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
379 if (info.noise_level_max)
380 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
381 else
382 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
383 } else {
384 *(outwalk++) = '?';
385 }
386 walk += strlen("noise");
387 }
388
389 if (BEGINS_WITH(walk+1, "essid")) {
390 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
391 outwalk += sprintf(outwalk, "%s", info.essid);
392 else
393 *(outwalk++) = '?';
394 walk += strlen("essid");
395 }
396
397 if (BEGINS_WITH(walk+1, "ip")) {
398 outwalk += sprintf(outwalk, "%s", ip_address);
399 walk += strlen("ip");
400 }
362 outwalk += sprintf(outwalk, "%d", info.quality);
363 } else {
364 *(outwalk++) = '?';
365 }
366 walk += strlen("quality");
367 }
368
369 if (BEGINS_WITH(walk + 1, "signal")) {
370 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
371 if (info.signal_level_max)
372 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
373 else
374 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
375 } else {
376 *(outwalk++) = '?';
377 }
378 walk += strlen("signal");
379 }
380
381 if (BEGINS_WITH(walk + 1, "noise")) {
382 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
383 if (info.noise_level_max)
384 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
385 else
386 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
387 } else {
388 *(outwalk++) = '?';
389 }
390 walk += strlen("noise");
391 }
392
393 if (BEGINS_WITH(walk + 1, "essid")) {
394 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
395 outwalk += sprintf(outwalk, "%s", info.essid);
396 else
397 *(outwalk++) = '?';
398 walk += strlen("essid");
399 }
400
401 if (BEGINS_WITH(walk + 1, "frequency")) {
402 if (info.flags & WIRELESS_INFO_FLAG_HAS_FREQUENCY)
403 outwalk += sprintf(outwalk, "%1.1f GHz", info.frequency / 1e9);
404 else
405 *(outwalk++) = '?';
406 walk += strlen("frequency");
407 }
408
409 if (BEGINS_WITH(walk + 1, "ip")) {
410 outwalk += sprintf(outwalk, "%s", ip_address);
411 walk += strlen("ip");
412 }
401413
402414 #ifdef LINUX
403 if (BEGINS_WITH(walk+1, "bitrate")) {
404 char br_buffer[128];
405
406 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
407
408 outwalk += sprintf(outwalk, "%s", br_buffer);
409 walk += strlen("bitrate");
410 }
411 #endif
412 }
415 if (BEGINS_WITH(walk + 1, "bitrate")) {
416 char br_buffer[128];
417
418 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
419
420 outwalk += sprintf(outwalk, "%s", br_buffer);
421 walk += strlen("bitrate");
422 }
423 #endif
424 }
413425
414426 out:
415 END_COLOR;
416 OUTPUT_FULL_TEXT(buffer);
427 END_COLOR;
428 OUTPUT_FULL_TEXT(buffer);
417429 }
0 // vim:ts=8:expandtab
0 // vim:ts=4:sw=4:expandtab
11 #include <stdbool.h>
22 #include <glob.h>
33 #include <string.h>
1414 * anything). kill() will return ESRCH if the process does not exist and 0 or
1515 * EPERM (depending on the uid) if it exists.
1616 *
17 * If multiple files match the glob pattern, all of them will be checked until
18 * the first running process is found.
19 *
1720 */
1821 bool process_runs(const char *path) {
19 static char pidbuf[16];
20 static glob_t globbuf;
21 memset(pidbuf, 0, sizeof(pidbuf));
22 static char pidbuf[16];
23 static glob_t globbuf;
24 memset(pidbuf, 0, sizeof(pidbuf));
2225
23 if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0)
24 die("glob() failed\n");
25 if (!slurp((globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path), pidbuf, sizeof(pidbuf))) {
26 globfree(&globbuf);
27 return false;
26 if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0)
27 die("glob() failed\n");
28 if (globbuf.gl_pathc == 0) {
29 /* No glob matches, the specified path does not contain a wildcard. */
30 globfree(&globbuf);
31 if (!slurp(path, pidbuf, sizeof(pidbuf)))
32 return false;
33 return (kill(strtol(pidbuf, NULL, 10), 0) == 0 || errno == EPERM);
34 }
35 for (size_t i = 0; i < globbuf.gl_pathc; i++) {
36 if (!slurp(globbuf.gl_pathv[i], pidbuf, sizeof(pidbuf))) {
37 globfree(&globbuf);
38 return false;
2839 }
29 globfree(&globbuf);
40 if (kill(strtol(pidbuf, NULL, 10), 0) == 0 || errno == EPERM) {
41 globfree(&globbuf);
42 return true;
43 }
44 }
45 globfree(&globbuf);
3046
31 return (kill(strtol(pidbuf, NULL, 10), 0) == 0 || errno == EPERM);
47 return false;
3248 }