My slstatus configuration
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

684 rindas
13 KiB

  1. /*
  2. * Copyright (C) 2016, drkhsh
  3. * Copyright (C) 2016, Ali H. Fardan (Raiz) <raiz@firemail.cc>
  4. * see LICENSE for copyright details
  5. */
  6. #define _GNU_SOURCE
  7. #define VERSION "2.0"
  8. #include <alsa/asoundlib.h>
  9. #include <err.h>
  10. #include <fcntl.h>
  11. #include <ifaddrs.h>
  12. #include <limits.h>
  13. #include <linux/wireless.h>
  14. #include <netdb.h>
  15. #include <pwd.h>
  16. #include <signal.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/ioctl.h>
  22. #include <sys/stat.h>
  23. #include <sys/statvfs.h>
  24. #include <sys/socket.h>
  25. #include <sys/sysinfo.h>
  26. #include <sys/types.h>
  27. #include <time.h>
  28. #include <unistd.h>
  29. #include <X11/Xlib.h>
  30. #undef strlcat
  31. #undef strlcpy
  32. #include "extern/arg.h"
  33. #include "extern/strlcat.h"
  34. #include "extern/strlcpy.h"
  35. #include "extern/concat.h"
  36. struct arg {
  37. char *(*func)();
  38. const char *fmt;
  39. const char *args;
  40. };
  41. static char *smprintf(const char *fmt, ...);
  42. static char *battery_perc(const char *bat);
  43. static char *battery_state(const char *bat);
  44. static char *cpu_perc(void);
  45. static char *datetime(const char *fmt);
  46. static char *disk_free(const char *mnt);
  47. static char *disk_perc(const char *mnt);
  48. static char *disk_total(const char *mnt);
  49. static char *disk_used(const char *mnt);
  50. static char *entropy(void);
  51. static char *gid(void);
  52. static char *hostname(void);
  53. static char *ip(const char *iface);
  54. static char *load_avg(void);
  55. static char *ram_free(void);
  56. static char *ram_perc(void);
  57. static char *ram_used(void);
  58. static char *ram_total(void);
  59. static char *run_command(const char *cmd);
  60. static char *temp(const char *file);
  61. static char *uid(void);
  62. static char *uptime(void);
  63. static char *username(void);
  64. static char *vol_perc(const char *card);
  65. static char *wifi_perc(const char *iface);
  66. static char *wifi_essid(const char *iface);
  67. static void set_status(const char *str);
  68. static void sighandler(const int signo);
  69. static void usage(void);
  70. char *argv0;
  71. char concat[];
  72. static unsigned short int delay;
  73. static unsigned short int done;
  74. static unsigned short int dflag, oflag;
  75. static Display *dpy;
  76. #include "config.h"
  77. static char *
  78. smprintf(const char *fmt, ...)
  79. {
  80. va_list ap;
  81. char *ret;
  82. int len;
  83. va_start(ap, fmt);
  84. len = vsnprintf(NULL, 0, fmt, ap);
  85. va_end(ap);
  86. ret = malloc(++len);
  87. if (ret == NULL)
  88. err(1, "malloc");
  89. va_start(ap, fmt);
  90. vsnprintf(ret, len, fmt, ap);
  91. va_end(ap);
  92. return ret;
  93. }
  94. static char *
  95. battery_perc(const char *bat)
  96. {
  97. int perc;
  98. FILE *fp;
  99. ccat(3, "/sys/class/power_supply/", bat, "/capacity");
  100. fp = fopen(concat, "r");
  101. if (fp == NULL) {
  102. warn("Failed to open file %s", concat);
  103. return smprintf(UNKNOWN_STR);
  104. }
  105. fscanf(fp, "%i", &perc);
  106. fclose(fp);
  107. return smprintf("%d%%", perc);
  108. }
  109. static char *
  110. battery_state(const char *bat)
  111. {
  112. char state[12];
  113. FILE *fp;
  114. ccat(3, "/sys/class/power_supply/", bat, "/status");
  115. fp = fopen(concat, "r");
  116. if (fp == NULL) {
  117. warn("Failed to open file %s", concat);
  118. return smprintf(UNKNOWN_STR);
  119. }
  120. fscanf(fp, "%12s", state);
  121. fclose(fp);
  122. if (strcmp(state, "Charging") == 0) {
  123. return smprintf("+");
  124. } else if (strcmp(state, "Discharging") == 0) {
  125. return smprintf("-");
  126. } else if (strcmp(state, "Full") == 0) {
  127. return smprintf("=");
  128. } else {
  129. return smprintf("?");
  130. }
  131. }
  132. static char *
  133. cpu_perc(void)
  134. {
  135. int perc;
  136. long double a[4], b[4];
  137. FILE *fp;
  138. fp = fopen("/proc/stat", "r");
  139. if (fp == NULL) {
  140. warn("Failed to open file /proc/stat");
  141. return smprintf(UNKNOWN_STR);
  142. }
  143. fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
  144. fclose(fp);
  145. delay = (UPDATE_INTERVAL - (UPDATE_INTERVAL - 1));
  146. sleep(delay);
  147. fp = fopen("/proc/stat", "r");
  148. if (fp == NULL) {
  149. warn("Failed to open file /proc/stat");
  150. return smprintf(UNKNOWN_STR);
  151. }
  152. fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
  153. fclose(fp);
  154. perc = 100 * ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) / ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3]));
  155. return smprintf("%d%%", perc);
  156. }
  157. static char *
  158. datetime(const char *fmt)
  159. {
  160. time_t t;
  161. char str[80];
  162. t = time(NULL);
  163. if (strftime(str, sizeof(str), fmt, localtime(&t)) == 0) {
  164. return smprintf(UNKNOWN_STR);
  165. }
  166. return smprintf("%s", str);
  167. }
  168. static char *
  169. disk_free(const char *mnt)
  170. {
  171. struct statvfs fs;
  172. if (statvfs(mnt, &fs) < 0) {
  173. warn("Failed to get filesystem info");
  174. return smprintf(UNKNOWN_STR);
  175. }
  176. return smprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
  177. }
  178. static char *
  179. disk_perc(const char *mnt)
  180. {
  181. int perc;
  182. struct statvfs fs;
  183. if (statvfs(mnt, &fs) < 0) {
  184. warn("Failed to get filesystem info");
  185. return smprintf(UNKNOWN_STR);
  186. }
  187. perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
  188. return smprintf("%d%%", perc);
  189. }
  190. static char *
  191. disk_total(const char *mnt)
  192. {
  193. struct statvfs fs;
  194. if (statvfs(mnt, &fs) < 0) {
  195. warn("Failed to get filesystem info");
  196. return smprintf(UNKNOWN_STR);
  197. }
  198. return smprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
  199. }
  200. static char *
  201. disk_used(const char *mnt)
  202. {
  203. struct statvfs fs;
  204. if (statvfs(mnt, &fs) < 0) {
  205. warn("Failed to get filesystem info");
  206. return smprintf(UNKNOWN_STR);
  207. }
  208. return smprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
  209. }
  210. static char *
  211. entropy(void)
  212. {
  213. int num;
  214. FILE *fp;
  215. fp= fopen("/proc/sys/kernel/random/entropy_avail", "r");
  216. if (fp == NULL) {
  217. warn("Failed to open file /proc/sys/kernel/random/entropy_avail");
  218. return smprintf(UNKNOWN_STR);
  219. }
  220. fscanf(fp, "%d", &num);
  221. fclose(fp);
  222. return smprintf("%d", num);
  223. }
  224. static char *
  225. gid(void)
  226. {
  227. return smprintf("%d", getgid());
  228. }
  229. static char *
  230. hostname(void)
  231. {
  232. char buf[HOST_NAME_MAX];
  233. FILE *fp;
  234. fp = fopen("/proc/sys/kernel/hostname", "r");
  235. if (fp == NULL) {
  236. warn("Failed to open file /proc/sys/kernel/hostname");
  237. return smprintf(UNKNOWN_STR);
  238. }
  239. fgets(buf, sizeof(buf), fp);
  240. buf[strlen(buf)-1] = '\0';
  241. fclose(fp);
  242. return smprintf("%s", buf);
  243. }
  244. static char *
  245. ip(const char *iface)
  246. {
  247. struct ifaddrs *ifaddr, *ifa;
  248. int s;
  249. char host[NI_MAXHOST];
  250. if (getifaddrs(&ifaddr) == -1) {
  251. warn("Failed to get IP address for interface %s", iface);
  252. return smprintf(UNKNOWN_STR);
  253. }
  254. for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  255. if (ifa->ifa_addr == NULL) {
  256. continue;
  257. }
  258. s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  259. if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
  260. if (s != 0) {
  261. warnx("Failed to get IP address for interface %s", iface);
  262. return smprintf(UNKNOWN_STR);
  263. }
  264. return smprintf("%s", host);
  265. }
  266. }
  267. freeifaddrs(ifaddr);
  268. return smprintf(UNKNOWN_STR);
  269. }
  270. static char *
  271. load_avg(void)
  272. {
  273. double avgs[3];
  274. if (getloadavg(avgs, 3) < 0) {
  275. warnx("Failed to get the load avg");
  276. return smprintf(UNKNOWN_STR);
  277. }
  278. return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
  279. }
  280. static char *
  281. ram_free(void)
  282. {
  283. long free;
  284. FILE *fp;
  285. fp = fopen("/proc/meminfo", "r");
  286. if (fp == NULL) {
  287. warn("Failed to open file /proc/meminfo");
  288. return smprintf(UNKNOWN_STR);
  289. }
  290. fscanf(fp, "MemFree: %ld kB\n", &free);
  291. fclose(fp);
  292. return smprintf("%f", (float)free / 1024 / 1024);
  293. }
  294. static char *
  295. ram_perc(void)
  296. {
  297. long total, free, buffers, cached;
  298. FILE *fp;
  299. fp = fopen("/proc/meminfo", "r");
  300. if (fp == NULL) {
  301. warn("Failed to open file /proc/meminfo");
  302. return smprintf(UNKNOWN_STR);
  303. }
  304. fscanf(fp, "MemTotal: %ld kB\n", &total);
  305. fscanf(fp, "MemFree: %ld kB\n", &free);
  306. fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
  307. fscanf(fp, "Cached: %ld kB\n", &cached);
  308. fclose(fp);
  309. return smprintf("%d%%", 100 * ((total - free) - (buffers + cached)) / total);
  310. }
  311. static char *
  312. ram_total(void)
  313. {
  314. long total;
  315. FILE *fp;
  316. fp = fopen("/proc/meminfo", "r");
  317. if (fp == NULL) {
  318. warn("Failed to open file /proc/meminfo");
  319. return smprintf(UNKNOWN_STR);
  320. }
  321. fscanf(fp, "MemTotal: %ld kB\n", &total);
  322. fclose(fp);
  323. return smprintf("%f", (float)total / 1024 / 1024);
  324. }
  325. static char *
  326. ram_used(void)
  327. {
  328. long free, total, buffers, cached;
  329. FILE *fp;
  330. fp = fopen("/proc/meminfo", "r");
  331. if (fp == NULL) {
  332. warn("Failed to open file /proc/meminfo");
  333. return smprintf(UNKNOWN_STR);
  334. }
  335. fscanf(fp, "MemTotal: %ld kB\n", &total);
  336. fscanf(fp, "MemFree: %ld kB\n", &free);
  337. fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
  338. fscanf(fp, "Cached: %ld kB\n", &cached);
  339. fclose(fp);
  340. return smprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024);
  341. }
  342. static char *
  343. run_command(const char *cmd)
  344. {
  345. FILE *fp;
  346. char buf[64] = "n/a";
  347. fp = popen(cmd, "r");
  348. if (fp == NULL) {
  349. warn("Failed to get command output for %s", cmd);
  350. return smprintf(UNKNOWN_STR);
  351. }
  352. fgets(buf, sizeof(buf), fp);
  353. buf[sizeof(buf)-1] = '\0';
  354. pclose(fp);
  355. return smprintf("%s", buf);
  356. }
  357. static char *
  358. temp(const char *file)
  359. {
  360. int temp;
  361. FILE *fp;
  362. fp = fopen(file, "r");
  363. if (fp == NULL) {
  364. warn("Failed to open file %s", file);
  365. return smprintf(UNKNOWN_STR);
  366. }
  367. fscanf(fp, "%d", &temp);
  368. fclose(fp);
  369. return smprintf("%d°C", temp / 1000);
  370. }
  371. static char *
  372. uptime(void)
  373. {
  374. struct sysinfo info;
  375. int h = 0;
  376. int m = 0;
  377. sysinfo(&info);
  378. h = info.uptime / 3600;
  379. m = (info.uptime - h * 3600 ) / 60;
  380. return smprintf("%dh %dm", h, m);
  381. }
  382. static char *
  383. username(void)
  384. {
  385. uid_t uid = geteuid();
  386. struct passwd *pw = getpwuid(uid);
  387. if (pw == NULL) {
  388. warn("Failed to get username");
  389. return smprintf(UNKNOWN_STR);
  390. }
  391. return smprintf("%s", pw->pw_name);
  392. }
  393. static char *
  394. uid(void)
  395. {
  396. return smprintf("%d", geteuid());
  397. }
  398. static char *
  399. vol_perc(const char *card)
  400. {
  401. long int vol, max, min;
  402. snd_mixer_t *handle;
  403. snd_mixer_elem_t *elem;
  404. snd_mixer_selem_id_t *s_elem;
  405. snd_mixer_open(&handle, 0);
  406. snd_mixer_attach(handle, card);
  407. snd_mixer_selem_register(handle, NULL, NULL);
  408. snd_mixer_load(handle);
  409. snd_mixer_selem_id_malloc(&s_elem);
  410. snd_mixer_selem_id_set_name(s_elem, "Master");
  411. elem = snd_mixer_find_selem(handle, s_elem);
  412. if (elem == NULL) {
  413. snd_mixer_selem_id_free(s_elem);
  414. snd_mixer_close(handle);
  415. warn("Failed to get volume percentage for %s", card);
  416. return smprintf(UNKNOWN_STR);
  417. }
  418. snd_mixer_handle_events(handle);
  419. snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
  420. snd_mixer_selem_get_playback_volume(elem, 0, &vol);
  421. snd_mixer_selem_id_free(s_elem);
  422. snd_mixer_close(handle);
  423. return smprintf("%d%%", ((uint_fast16_t)(vol * 100) / max));
  424. }
  425. static char *
  426. wifi_perc(const char *iface)
  427. {
  428. int perc;
  429. char buf[255];
  430. char *datastart;
  431. char status[5];
  432. FILE *fp;
  433. ccat(3, "/sys/class/net/", iface, "/operstate");
  434. fp = fopen(concat, "r");
  435. if (fp == NULL) {
  436. warn("Failed to open file %s", concat);
  437. return smprintf(UNKNOWN_STR);
  438. }
  439. fgets(status, 5, fp);
  440. fclose(fp);
  441. if(strcmp(status, "up\n") != 0) {
  442. return smprintf(UNKNOWN_STR);
  443. }
  444. fp = fopen("/proc/net/wireless", "r");
  445. if (fp == NULL) {
  446. warn("Failed to open file /proc/net/wireless");
  447. return smprintf(UNKNOWN_STR);
  448. }
  449. ccat(2, iface, ":");
  450. fgets(buf, sizeof(buf), fp);
  451. fgets(buf, sizeof(buf), fp);
  452. fgets(buf, sizeof(buf), fp);
  453. fclose(fp);
  454. datastart = strstr(buf, concat);
  455. if (datastart != NULL) {
  456. datastart = strstr(buf, ":");
  457. sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
  458. }
  459. return smprintf("%d%%", perc);
  460. }
  461. static char *
  462. wifi_essid(const char *iface)
  463. {
  464. char id[IW_ESSID_MAX_SIZE+1];
  465. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  466. struct iwreq wreq;
  467. memset(&wreq, 0, sizeof(struct iwreq));
  468. wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
  469. sprintf(wreq.ifr_name, iface);
  470. if (sockfd == -1) {
  471. warn("Failed to get ESSID for interface %s", iface);
  472. return smprintf(UNKNOWN_STR);
  473. }
  474. wreq.u.essid.pointer = id;
  475. if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
  476. warn("Failed to get ESSID for interface %s", iface);
  477. return smprintf(UNKNOWN_STR);
  478. }
  479. close(sockfd);
  480. if (strcmp((char *)wreq.u.essid.pointer, "") == 0)
  481. return smprintf(UNKNOWN_STR);
  482. else
  483. return smprintf("%s", (char *)wreq.u.essid.pointer);
  484. }
  485. static void
  486. set_status(const char *str)
  487. {
  488. XStoreName(dpy, DefaultRootWindow(dpy), str);
  489. XSync(dpy, False);
  490. }
  491. static void
  492. sighandler(const int signo)
  493. {
  494. if (signo == SIGTERM || signo == SIGINT) {
  495. done = 1;
  496. }
  497. }
  498. static void
  499. usage(void)
  500. {
  501. fprintf(stderr, "usage: %s [-dhov]\n", argv0);
  502. exit(1);
  503. }
  504. int
  505. main(int argc, char *argv[])
  506. {
  507. unsigned short int i;
  508. char status_string[4096];
  509. char *res, *element;
  510. struct arg argument;
  511. struct sigaction act;
  512. ARGBEGIN {
  513. case 'd':
  514. dflag = 1;
  515. break;
  516. case 'o':
  517. oflag = 1;
  518. break;
  519. case 'v':
  520. printf("slstatus %s (C) 2016 slstatus engineers\n", VERSION);
  521. return 0;
  522. default:
  523. usage();
  524. } ARGEND
  525. if (dflag && oflag) {
  526. usage();
  527. }
  528. if (dflag) {
  529. (void)daemon(1, 1);
  530. }
  531. memset(&act, 0, sizeof(act));
  532. act.sa_handler = sighandler;
  533. sigaction(SIGINT, &act, 0);
  534. sigaction(SIGTERM, &act, 0);
  535. if (!oflag) {
  536. dpy = XOpenDisplay(NULL);
  537. }
  538. while (!done) {
  539. status_string[0] = '\0';
  540. for (i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
  541. argument = args[i];
  542. if (argument.args == NULL) {
  543. res = argument.func();
  544. } else {
  545. res = argument.func(argument.args);
  546. }
  547. element = smprintf(argument.fmt, res);
  548. if (element == NULL) {
  549. element = smprintf(UNKNOWN_STR);
  550. warnx("Failed to format output");
  551. }
  552. strlcat(status_string, element, sizeof(status_string));
  553. free(res);
  554. free(element);
  555. }
  556. if (!oflag) {
  557. set_status(status_string);
  558. } else {
  559. printf("%s\n", status_string);
  560. }
  561. /*
  562. * subtract delay time spend in function
  563. * calls from the actual global delay time
  564. */
  565. sleep(UPDATE_INTERVAL - delay);
  566. delay = 0;
  567. }
  568. if (!oflag) {
  569. set_status(NULL);
  570. XCloseDisplay(dpy);
  571. }
  572. return 0;
  573. }