commands over unix socket
[pandora_liveinfo.git] / main.c
CommitLineData
063ae4be 1/*
2 * pandora live info
3 * (C) notaz, 2014
4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
8
9#include <stdio.h>
15f42220 10#include <stdlib.h>
063ae4be 11#include <string.h>
12#include <stdarg.h>
13#include <pthread.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17#include <sys/ioctl.h>
18#include <sys/mman.h>
19#include <unistd.h>
20#include <sys/time.h>
21#include <time.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <signal.h>
25#include <poll.h>
26#include <linux/fb.h>
27#include <linux/omapfb.h>
28#include <stdint.h>
29#include "fonts.h"
30
31#define SCREEN_WIDTH 800
32#define SCREEN_HEIGHT 480
33#define WIDTH 80
34#define HEIGHT 480
35#define MEM_SIZE (((WIDTH * HEIGHT * 2 * 2) + 0xfff) & ~0xfff)
36#define Y_STEP 9
37
38static struct fb_var_screeninfo g_vi;
39static uint16_t *g_screen_base, *g_screen;
40static unsigned int g_old_mem;
15f42220 41static int g_flip_id;
42static int g_exit, g_hide;
43static pthread_cond_t g_cond;
063ae4be 44
b7d8fc1a 45#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
063ae4be 46#define IS_START(buf, str) \
47 !strncmp(buf, str, sizeof(str) - 1)
48
15f42220 49static void clear_bytes(void *mem, int bytes);
50
51static int setup_layer(int fd)
063ae4be 52{
063ae4be 53 struct omapfb_plane_info pi;
54 struct omapfb_mem_info mi;
55 struct omapfb_color_key key;
56 int ret;
57
15f42220 58 ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
063ae4be 59 if (ret < 0) {
60 perror("ioctl OMAPFB_QUERY_PLANE");
61 return 1;
62 }
63
15f42220 64 ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
063ae4be 65 if (ret < 0) {
66 perror("ioctl OMAPFB_QUERY_MEM");
67 return 1;
68 }
69
70 /* must disable when changing stuff */
71 if (pi.enabled) {
72 pi.enabled = 0;
15f42220 73 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
063ae4be 74 if (ret < 0) {
75 perror("ioctl OMAPFB_SETUP_PLANE (d)");
76 return 1;
77 }
78 }
79
80 g_old_mem = mi.size;
81 if (mi.size < MEM_SIZE) {
82 mi.size = MEM_SIZE;
15f42220 83 ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
063ae4be 84 if (ret < 0) {
85 perror("ioctl SETUP_MEM");
86 return 1;
87 }
88 }
89
90 pi.pos_x = SCREEN_WIDTH - WIDTH;
91 pi.pos_y = 0;
92 pi.out_width = WIDTH;
93 pi.out_height = HEIGHT;
15f42220 94 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
063ae4be 95 if (ret < 0) {
96 perror("ioctl OMAPFB_SETUP_PLANE (e1)");
97 return 1;
98 }
99
15f42220 100 ret = ioctl(fd, FBIOGET_VSCREENINFO, &g_vi);
063ae4be 101 if (ret < 0) {
102 perror("ioctl FBIOGET_VSCREENINFO");
103 return 1;
104 }
105
106 g_vi.xres = g_vi.xres_virtual = WIDTH;
107 g_vi.yres = HEIGHT;
108 g_vi.yres_virtual = HEIGHT * 2;
109 g_vi.bits_per_pixel = 16;
110
15f42220 111 ret = ioctl(fd, FBIOPUT_VSCREENINFO, &g_vi);
063ae4be 112 if (ret < 0) {
113 perror("ioctl FBIOPUT_VSCREENINFO");
114 return 1;
115 }
116
117 pi.enabled = 1;
15f42220 118 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
063ae4be 119 if (ret < 0) {
120 perror("ioctl OMAPFB_SETUP_PLANE (e2)");
121 return 1;
122 }
123
124 memset(&key, 0, sizeof(key));
125 key.key_type = OMAPFB_COLOR_KEY_VID_SRC;
126 key.trans_key = 0x07e0;
127
15f42220 128 ret = ioctl(fd, OMAPFB_SET_COLOR_KEY, &key);
129 if (ret < 0) {
130 perror("ioctl OMAPFB_SET_COLOR_KEY");
063ae4be 131 return 1;
15f42220 132 }
133
134 g_screen_base = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE,
135 MAP_SHARED, fd, 0);
136 if (g_screen_base == MAP_FAILED) {
137 perror("mmap");
138 g_screen = g_screen_base = NULL;
139 return 1;
140 }
141 clear_bytes(g_screen_base, MEM_SIZE);
142 g_screen = g_screen_base;
143 g_flip_id = 0;
063ae4be 144
145 return 0;
146}
147
15f42220 148static int check_layer(int fd)
063ae4be 149{
150 struct omapfb_plane_info pi;
151 int ret;
152
15f42220 153 ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
063ae4be 154 if (ret < 0) {
155 perror("ioctl OMAPFB_QUERY_PLANE");
156 return 1;
157 }
158
159 if (!pi.enabled) {
160 printf("something disabled the layer (tv-out?), quitting\n");
161 return 1;
162 }
163
164 return 0;
165}
166
15f42220 167static void remove_layer(int fd)
063ae4be 168{
169 struct omapfb_plane_info pi;
170 struct omapfb_mem_info mi;
171 int ret;
172
15f42220 173 if (g_screen_base != NULL) {
174 munmap(g_screen_base, MEM_SIZE);
175 g_screen = g_screen_base = NULL;
176 }
177
063ae4be 178 memset(&pi, 0, sizeof(pi));
179 pi.enabled = 0;
15f42220 180 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
063ae4be 181 if (ret < 0)
182 perror("ioctl OMAPFB_SETUP_PLANE (c)");
183
15f42220 184 ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
063ae4be 185 if (ret < 0) {
186 perror("ioctl OMAPFB_QUERY_MEM");
187 goto out;
188 }
189
190 if (mi.size != g_old_mem) {
191 mi.size = g_old_mem;
15f42220 192 ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
063ae4be 193 if (ret < 0) {
194 perror("ioctl SETUP_MEM");
195 goto out;
196 }
197 }
198
15f42220 199out:;
063ae4be 200}
201
15f42220 202static void flip_fb(int fd)
063ae4be 203{
15f42220 204 g_vi.yoffset = g_flip_id * HEIGHT;
205 ioctl(fd, FBIOPAN_DISPLAY, &g_vi);
206 g_flip_id ^= 1;
207 g_screen = g_screen_base + g_flip_id * WIDTH * HEIGHT;
063ae4be 208}
209
15f42220 210static void handle_term(int num)
063ae4be 211{
15f42220 212 g_exit = 1;
213 pthread_cond_signal(&g_cond);
214}
063ae4be 215
15f42220 216static void handle_usr1(int num)
217{
218 g_hide = !g_hide;
219 pthread_cond_signal(&g_cond);
063ae4be 220}
221
b7d8fc1a 222static struct {
223 char text[16];
224 int idle;
225} user_msgs[16];
226
227static int handle_socket(int sock)
228{
229 char buf[256], *p;
230 int i, ret;
231
232 ret = recv(sock, buf, sizeof(buf) - 1, 0);
233 if (ret < 0) {
234 perror("recv");
235 return ret;
236 }
237 if (ret == 0)
238 return 0;
239
240 buf[ret] = 0;
241 p = strchr(buf, ':');
242 if (p != NULL) {
243 for (i = 0; i < ARRAY_SIZE(user_msgs); i++) {
244 if (user_msgs[i].text[0] == 0)
245 break;
246 if (!strncmp(user_msgs[i].text, buf, p - buf + 1))
247 break;
248 }
249 if (i == ARRAY_SIZE(user_msgs)) {
250 printf("out of user_msg slots\n");
251 return 0;
252 }
253 memcpy(user_msgs[i].text, buf, sizeof(user_msgs[i].text) - 1);
254 user_msgs[i].text[sizeof(user_msgs[i].text) - 1] = 0;
255 user_msgs[i].idle = 0;
256 }
257 else if (!strcmp(buf, "poke")) {
258 // if hidden, show up
259 // if visible, exit
260 if (g_hide) {
261 g_hide = 0;
262 return 1;
263 }
264 g_exit = 1;
265 return 1;
266 }
267 else if (!strcmp(buf, "hide")) {
268 g_hide = 1;
269 return 1;
270 }
271 else if (!strcmp(buf, "show")) {
272 g_hide = 0;
273 return 1;
274 }
275 else if (!strcmp(buf, "quit")) {
276 g_exit = 1;
277 return 1;
278 }
279 else {
280 printf("unknown command: '%s'\n", buf);
281 }
282
283 return 0;
284}
285
063ae4be 286#define s_printf(x, y, fmt, ...) \
287 basic_text_out16(g_screen, WIDTH, x, y, fmt, ##__VA_ARGS__);
288
289static int read_int_file(const char *fn, int *val)
290{
291 FILE *f;
292 int ret;
293
294 *val = 0;
295 f = fopen(fn, "r");
296 if (f == NULL)
297 return 1;
298 ret = fscanf(f, "%d", val);
299 fclose(f);
300 if (ret != 1)
301 return 1;
302
303 return 0;
304}
305
15f42220 306static void clear_bytes(void *mem, int bytes)
063ae4be 307{
15f42220 308 int *p = mem;
309 int l = bytes / 4;
063ae4be 310
311 for (; l >= 4; l -= 4, p += 4)
312 p[0] = p[1] = p[2] = p[3] = 0x07e007e0;
313 for (; l > 0; l--, p++)
314 *p = 0x07e007e0;
315}
316
15f42220 317static void clear(int h)
318{
319 clear_bytes(g_screen, WIDTH * h * 2);
320}
321
063ae4be 322struct proc_stat {
323 unsigned long idlesum;
324 unsigned long sys;
325 unsigned long irqs;
326 unsigned long ctxt;
327};
328
329static struct {
330 struct proc_stat last_st;
331 int cpu_usage;
332 int cpu_sys;
333 int irqs;
334 int ctxt;
335 int mem_free;
336 int mem_huge;
337 int mem_free_swap;
338} stats;
339
340static void collect_proc_stat(void)
341{
342 static long hz;
343 struct proc_stat st;
344 char buf[256];
345 unsigned long wait;
346 unsigned long iowait;
347 FILE *f;
348
349 if (hz == 0) {
350 hz = sysconf(_SC_CLK_TCK);
351 printf("hz: %ld\n", hz);
352 }
353
354 f = fopen("/proc/stat", "r");
355 if (f == NULL)
356 return;
357
358 if (fscanf(f, "cpu %*s %*s %lu %lu %lu",
359 &st.sys, &wait, &iowait) != 3)
360 goto out;
361 do {
362 if (fgets(buf, sizeof(buf), f) == NULL)
363 goto out;
364 } while (fscanf(f, "intr %lu", &st.irqs) != 1);
365 do {
366 if (fgets(buf, sizeof(buf), f) == NULL)
367 goto out;
368 } while (fscanf(f, "ctxt %lu", &st.ctxt) != 1);
369
370 st.idlesum = wait + iowait;
371
372 stats.cpu_usage = hz - (st.idlesum - stats.last_st.idlesum);
373 stats.cpu_sys = st.sys - stats.last_st.sys;
374 if (hz != 100) {
375 stats.cpu_usage = stats.cpu_usage * 100 / hz;
376 stats.cpu_sys = stats.cpu_sys * 100 / hz;
377 }
378 stats.irqs = st.irqs - stats.last_st.irqs;
379 stats.ctxt = st.ctxt - stats.last_st.ctxt;
380
381out:
382 stats.last_st = st;
383 fclose(f);
384}
385
386static void collect_mem_stat(void)
387{
388 static const char fn[] = "/proc/meminfo";
389 uint32_t total = 0, free = 0, buffers = 0, cached = 0;
390 uint32_t anonhuge = 0, hugetot = 0, hugefree = 0, hugepgsz = 0;
391 uint32_t free_swap = 0;
392 char buf[128];
393 FILE *f;
394
395 f = fopen(fn, "r");
396 if (f == NULL)
397 return;
398
399 while (fgets(buf, sizeof(buf), f)) {
400 if (total == 0 && sscanf(buf, "MemTotal: %u", &total) == 1)
401 continue;
402 if (free == 0 && sscanf(buf, "MemFree: %u", &free) == 1)
403 continue;
404 if (buffers == 0 && sscanf(buf, "Buffers: %u", &buffers) == 1)
405 continue;
406 if (cached == 0 && sscanf(buf, "Cached: %u", &cached) == 1)
407 continue;
408 if (free_swap == 0 && sscanf(buf, "SwapFree: %u", &free_swap) == 1)
409 continue;
410 if (anonhuge == 0 && sscanf(buf, "AnonHugePages: %u", &anonhuge) == 1)
411 continue;
412 if (hugetot == 0 && sscanf(buf, "HugePages_Total: %u", &hugetot) == 1)
413 continue;
414 if (hugefree == 0 && sscanf(buf, "HugePages_Free: %u", &hugefree) == 1)
415 continue;
416 if (hugepgsz == 0 && sscanf(buf, "Hugepagesize: %u", &hugepgsz) == 1)
417 continue;
418 }
419
420 fclose(f);
421
422 hugetot = (hugetot - hugefree) * hugepgsz;
423 free += buffers + cached;
424 stats.mem_free = free >> 10;
425 stats.mem_huge = hugetot >> 10;
426 stats.mem_free_swap = free_swap >> 10;
427}
428
429struct io_stat {
430 unsigned long sec_r;
431 unsigned long sec_w;
432};
433
434static struct {
435 struct io_stat last_st;
436 int read; // kB/s
437 int write;
438} io_stats;
439
440static void collect_io_stat(void)
441{
442 unsigned long sec_r, sec_w;
443 struct io_stat st = { 0, };
444 char buf[128];
445 FILE *f;
446 int i;
447
448 for (i = 0; i < 2; i++) {
449 snprintf(buf, sizeof(buf), "/sys/block/mmcblk%d/stat", i);
450 f = fopen(buf, "r");
451 if (f == NULL)
452 continue;
453
454 if (fscanf(f, "%*s %*s %lu %*s %*s %*s %lu",
455 &sec_r, &sec_w) == 2)
456 {
457 st.sec_r += sec_r;
458 st.sec_w += sec_w;
459 }
460 fclose(f);
461 }
462
463 io_stats.read = st.sec_r - io_stats.last_st.sec_r;
464 io_stats.write = st.sec_w - io_stats.last_st.sec_w;
465 // assuming 512 byte sectors..
466 io_stats.read >>= 1;
467 io_stats.write >>= 1;
468
469 io_stats.last_st = st;
470}
471
472struct net_stat {
473 unsigned long rx;
474 unsigned long tx;
475};
476
477static struct {
478 struct net_stat last_st;
479 int down; // kB/s
480 int up;
481 int have_wlan;
482 int link;
483 int level;
484} net_stats;
485
486static void collect_net_stat(void)
487{
488 struct net_stat st = { 0, };
489 unsigned long rx, tx;
490 int found = 0;
491 char buf[256];
492 FILE *f;
493
494 net_stats.down = net_stats.up =
495 net_stats.have_wlan = net_stats.link = net_stats.level = 0;
496
497 f = fopen("/proc/net/dev", "r");
498 if (f == NULL)
499 return;
500
501 while (!feof(f)) {
502 static const char fmt[] =
503 "%255s %lu %*s %*s %*s %*s %*s %*s %lu";
504 if (fscanf(f, fmt, buf, &rx, &tx) != 3)
505 continue;
506 if (IS_START(buf, "lo"))
507 continue;
508 st.rx += rx;
509 st.tx += tx;
510 found = 1;
511 }
512 fclose(f);
513
514 if (found) {
515 net_stats.down = st.rx - net_stats.last_st.rx;
516 net_stats.up = st.tx - net_stats.last_st.tx;
517 }
518 net_stats.last_st = st;
519
520 f = fopen("/proc/net/wireless", "r");
521 if (f == NULL)
522 return;
523
524 while (!feof(f)) {
525 int lnk, lvl;
526 if (fscanf(f, "%255s %*x %d. %d.", buf, &lnk, &lvl) != 3)
527 continue;
528 if (IS_START(buf, "lo"))
529 continue;
530 // first one should be enough
531 net_stats.have_wlan = 1;
532 net_stats.link = lnk;
533 net_stats.level = lvl;
534 break;
535 }
536 fclose(f);
537}
538
539static void collect_stats(void)
540{
541 collect_proc_stat();
542 collect_mem_stat();
543 collect_io_stat();
544 collect_net_stat();
545}
546
547static char cpu_reg_path[64];
548
549static void init_stats(void)
550{
551 char buf[64];
552 int found;
553 FILE *f;
554 int i;
555
556 // find the CPU regulator
557 for (i = found = 0; ; i++) {
558 snprintf(buf, sizeof(buf),
559 "/sys/class/regulator/regulator.%d/name", i);
560 f = fopen(buf, "r");
561 if (f == NULL)
562 break;
563 fgets(buf, sizeof(buf), f);
564 fclose(f);
565 if (IS_START(buf, "vdd_mpu")) {
566 found = 1;
567 break;
568 }
569 }
570
571 if (found)
572 snprintf(cpu_reg_path, sizeof(cpu_reg_path),
573 "/sys/class/regulator/regulator.%d/microvolts", i);
574
575 // do collect so differential stats get sane values
576 collect_stats();
577}
578
579static void get_time(int x, int y)
580{
581 struct timeval tv;
582 struct tm *t;
583 char buf[16];
584
585 gettimeofday(&tv, NULL);
586 t = localtime(&tv.tv_sec);
587 strftime(buf, sizeof(buf), "%T", t);
588 s_printf(x, y, " %s", buf);
589}
590
591static void get_cpu(int x, int y)
592{
593 s_printf(x, y, "CPU:%5d%%", stats.cpu_usage);
594}
595
596static void get_sys(int x, int y)
597{
598 s_printf(x, y, "SYS:%5d%%", stats.cpu_sys);
599}
600
601static void get_irq(int x, int y)
602{
603 s_printf(x, y, "IRQ:%5u", stats.irqs);
604}
605
606static void get_cs(int x, int y)
607{
608 s_printf(x, y, "CS:%6u", stats.ctxt);
609}
610
611static void get_cpuf(int x, int y)
612{
613 static const char fn[] =
614 "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
615 int f;
616
617 if (read_int_file(fn, &f))
618 return;
619 s_printf(x, y, "f:%7dM", f / 1000);
620}
621
622static void get_cpuv(int x, int y)
623{
624 int v = 0;
625
626 if (!cpu_reg_path[0] || read_int_file(cpu_reg_path, &v))
627 return;
628 s_printf(x, y, "V:%7.3fV", (float)v / 1000000.0f);
629}
630
631static void get_memfree(int x, int y)
632{
633 s_printf(x, y, "M:%7dM", stats.mem_free);
634}
635
636static void get_memhuge(int x, int y)
637{
638 s_printf(x, y, "H:%7dM", stats.mem_huge);
639}
640
641static void get_memswap(int x, int y)
642{
643 s_printf(x, y, "S:%7dM", stats.mem_free_swap);
644}
645
646#define PS_BASE "/sys/class/power_supply/bq27500-0/"
647
648static void get_bcap(int x, int y)
649{
650 static const char fnc[] = PS_BASE "capacity";
651 int c;
652
653 if (read_int_file(fnc, &c))
654 return;
655 s_printf(x, y, "C:%7d%%", c);
656}
657
658static void get_btime(int x, int y)
659{
660 static const char fne[] = PS_BASE "time_to_empty_now";
661 static const char fnf[] = PS_BASE "time_to_full_now";
662 int t = 0;
663
664 if (read_int_file(fne, &t) || t == 0) {
665 if (read_int_file(fnf, &t))
666 return;
667 }
668 s_printf(x, y, "t:%4d:%02d", t / 3600, t / 60 % 60);
669}
670
671static void get_bvolts(int x, int y)
672{
673 static const char fnv[] = PS_BASE "voltage_now";
674 int volt = 0;
675
676 if (read_int_file(fnv, &volt))
677 return;
678
679 s_printf(x, y, "V:%7.3fV", (float)volt / 1000000.0f);
680}
681
682static void get_bwatts(int x, int y)
683{
684 static const char fnc[] = PS_BASE "current_now";
685 static const char fnv[] = PS_BASE "voltage_now";
686 int w, cur = 0, volt = 0;
687
688 if (read_int_file(fnc, &cur))
689 return;
690 if (read_int_file(fnv, &volt))
691 return;
692
693 w = (cur / 1000) * (volt / 1000);
694 s_printf(x, y, "P:%7.3fW", (float)w / 1000000.0f);
695}
696
697static void get_btemp(int x, int y)
698{
699 static const char fnt[] = PS_BASE "temp";
700 int t;
701
702 if (read_int_file(fnt, &t))
703 return;
704 s_printf(x, y, "T:%7.1fC", (float)t / 10.0f);
705}
706
707static void get_ioread(int x, int y)
708{
709 s_printf(x, y, "R:%5.1fM/s", (float)io_stats.read / 1000.0f);
710}
711
712static void get_iowrite(int x, int y)
713{
714 s_printf(x, y, "W:%5.1fM/s", (float)io_stats.write / 1000.0f);
715}
716
717static void get_netdown(int x, int y)
718{
719 s_printf(x, y, "D:%5uK/s", net_stats.down / 1000);
720}
721
722static void get_netup(int x, int y)
723{
724 s_printf(x, y, "U:%5uK/s", net_stats.up / 1000);
725}
726
727static void get_netsgnl(int x, int y)
728{
729 s_printf(x, y, "S:%5ddBm", net_stats.level);
730}
731
732int main(int argc, char *argv[])
733{
15f42220 734 static const char socket_name[] = "\0liveinfo";
735 static const char fbname[] = "/dev/fb2";
063ae4be 736 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
063ae4be 737 pthread_condattr_t condattr;
738 struct sockaddr_un sun;
739 struct timespec ts;
740 struct pollfd pfd;
15f42220 741 const char *p;
742 int is_hidden = 0;
063ae4be 743 int y = 0, y_max = 0;
15f42220 744 int fd = -1;
063ae4be 745 int sock;
b7d8fc1a 746 int i, ret;
063ae4be 747
748 // look for other instance
b7d8fc1a 749 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
063ae4be 750 if (sock == -1) {
751 perror("socket PF_UNIX");
752 return 1;
753 }
754
755 memset(&sun, 0, sizeof(sun));
756 sun.sun_family = AF_UNIX;
757 memcpy(sun.sun_path, socket_name, sizeof(socket_name));
758
759 ret = connect(sock, (struct sockaddr *)&sun, sizeof(sun));
760 if (ret == 0) {
15f42220 761 printf("other instance detected, sending poke command\n");
b7d8fc1a 762 ret = send(sock, "poke", 4, 0);
763 if (ret != 4)
063ae4be 764 perror("send");
765 close(sock);
b7d8fc1a 766 return ret == 4 ? 0 : 1;
15f42220 767 }
768
769 fd = open(fbname, O_RDWR);
770 if (fd == -1) {
771 fprintf(stderr, "open %s: ", fbname);
772 perror(NULL);
773 return 1;
063ae4be 774 }
775
15f42220 776 nice(-1);
777
778 // no need for privileges any more
779 p = getenv("SUDO_UID");
780 if (p != NULL) {
781 ret = atoi(p);
782 if (ret != 0) {
783 ret = setuid(ret);
784 if (ret)
785 perror("setuid");
786 }
787 }
788
789 // bind/listen for commands
063ae4be 790 ret = bind(sock, (struct sockaddr *)&sun, sizeof(sun));
791 if (ret != 0) {
792 perror("bind");
793 close(sock);
794 return 1;
795 }
796
b7d8fc1a 797#if 0
063ae4be 798 ret = listen(sock, 1);
799 if (ret != 0) {
800 perror("listen");
801 close(sock);
802 return 1;
803 }
b7d8fc1a 804#endif
063ae4be 805
806 pfd.fd = sock;
807 pfd.events = POLLIN | POLLPRI;
808 pfd.revents = 0;
809
063ae4be 810 ret = pthread_condattr_init(&condattr);
811 ret |= pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
15f42220 812 ret |= pthread_cond_init(&g_cond, &condattr);
063ae4be 813 pthread_condattr_destroy(&condattr);
814 if (ret != 0) {
815 fprintf(stderr, "cond init failed\n");
816 return 1;
817 }
818
15f42220 819 ret = setup_layer(fd);
063ae4be 820 if (ret)
821 return ret;
822
15f42220 823 // clean up on kill too
824 signal(SIGTERM, handle_term);
825 signal(SIGUSR1, handle_usr1);
063ae4be 826
827 pthread_mutex_lock(&mutex);
828 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
829 if (ret != 0) {
830 perror("clock_gettime CLOCK_MONOTONIC");
831 return 1;
832 }
833
063ae4be 834 init_stats();
835
15f42220 836 while (!g_exit)
837 {
b7d8fc1a 838 // anything on unix socket?
839 ret = poll(&pfd, 1, 0);
840 if (ret < 0) {
841 perror("poll");
842 break;
843 }
844 if (ret > 0) {
845 ret = handle_socket(sock);
846 if (ret < 0)
847 break;
848 continue;
849 }
850
15f42220 851 // handle hiding
852 if (g_hide) {
853 if (!is_hidden) {
854 remove_layer(fd);
855 is_hidden = 1;
856 }
857 goto do_sleep;
858 }
859 else if (is_hidden) {
860 ret = setup_layer(fd);
861 if (ret)
862 break;
863 is_hidden = 0;
864 }
865
b7d8fc1a 866 if (check_layer(fd) != 0)
867 break;
868
063ae4be 869 collect_stats();
870
871 y += Y_STEP;
872 if (y > y_max)
873 y_max = y;
874 clear(y_max);
875
876 y = 0;
877 get_time (0, y += Y_STEP);
878 y += Y_STEP / 2;
879 get_cpu (0, y += Y_STEP);
880 get_sys (0, y += Y_STEP);
881 get_irq (0, y += Y_STEP);
882 get_cs (0, y += Y_STEP);
883 get_cpuf (0, y += Y_STEP);
884 get_cpuv (0, y += Y_STEP);
885 y += Y_STEP / 2;
886 s_printf(0, y += Y_STEP, "mem");
887 get_memfree(0, y += Y_STEP);
888 get_memswap(0, y += Y_STEP);
889 if (stats.mem_huge)
890 get_memhuge(0, y += Y_STEP);
891 y += Y_STEP / 2;
892 s_printf(0, y += Y_STEP, "i/o");
893 get_ioread (0, y += Y_STEP);
894 get_iowrite(0, y += Y_STEP);
895 y += Y_STEP / 2;
896 s_printf(0, y += Y_STEP, "net");
897 get_netdown(0, y += Y_STEP);
898 get_netup (0, y += Y_STEP);
899 if (net_stats.have_wlan)
900 get_netsgnl(0, y += Y_STEP);
901 y += Y_STEP / 2;
902 s_printf(0, y += Y_STEP, "batt");
903 get_bcap (0, y += Y_STEP);
904 get_btime (0, y += Y_STEP);
905 get_bvolts (0, y += Y_STEP);
906 get_bwatts (0, y += Y_STEP);
907 get_btemp (0, y += Y_STEP);
908
b7d8fc1a 909 // print user messages
910 y += Y_STEP;
911 for (i = 0; i < ARRAY_SIZE(user_msgs); i++) {
912 if (user_msgs[i].text[0] == 0)
913 break;
914 user_msgs[i].idle++;
915 if (user_msgs[i].idle > 6) {
916 // drop old entry, shift others up
917 memmove(&user_msgs[i], &user_msgs[i + 1],
918 (ARRAY_SIZE(user_msgs) - i - 1) * sizeof(user_msgs[0]));
919 user_msgs[ARRAY_SIZE(user_msgs) - 1].text[0] = 0;
920 // reprocess
921 i--;
922 continue;
923 }
15f42220 924
b7d8fc1a 925 s_printf(0, y += Y_STEP, user_msgs[i].text);
063ae4be 926 }
927
b7d8fc1a 928 flip_fb(fd);
929
15f42220 930do_sleep:
063ae4be 931 ts.tv_sec++;
15f42220 932 pthread_cond_timedwait(&g_cond, &mutex, &ts);
063ae4be 933 }
934
15f42220 935 remove_layer(fd);
936 close(fd);
063ae4be 937 close(sock);
938
939 return 0;
940}
941
942// vim:expandtab:sw=2:ts=2