My slstatus configuration
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

873 satır
18 KiB

  1. /* See LICENSE file for copyright and license details. */
  2. #include <dirent.h>
  3. #include <err.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <ifaddrs.h>
  7. #include <limits.h>
  8. #include <linux/wireless.h>
  9. #include <netdb.h>
  10. #include <pwd.h>
  11. #include <signal.h>
  12. #include <stdarg.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/stat.h>
  18. #include <sys/statvfs.h>
  19. #include <sys/socket.h>
  20. #include <sys/soundcard.h>
  21. #include <sys/sysinfo.h>
  22. #include <sys/types.h>
  23. #include <sys/utsname.h>
  24. #include <time.h>
  25. #include <unistd.h>
  26. #include <X11/Xlib.h>
  27. #include "arg.h"
  28. #define LEN(x) (sizeof (x) / sizeof *(x))
  29. struct arg {
  30. const char *(*func)();
  31. const char *fmt;
  32. const char *args;
  33. };
  34. static const char *battery_perc(const char *bat);
  35. static const char *battery_power(const char *bat);
  36. static const char *battery_state(const char *bat);
  37. static const char *cpu_freq(void);
  38. static const char *cpu_perc(void);
  39. static const char *datetime(const char *fmt);
  40. static const char *disk_free(const char *mnt);
  41. static const char *disk_perc(const char *mnt);
  42. static const char *disk_total(const char *mnt);
  43. static const char *disk_used(const char *mnt);
  44. static const char *entropy(void);
  45. static const char *gid(void);
  46. static const char *hostname(void);
  47. static const char *ipv4(const char *iface);
  48. static const char *ipv6(const char *iface);
  49. static const char *kernel_release(void);
  50. static const char *keyboard_indicators(void);
  51. static const char *load_avg(const char *fmt);
  52. static const char *num_files(const char *dir);
  53. static const char *ram_free(void);
  54. static const char *ram_perc(void);
  55. static const char *ram_used(void);
  56. static const char *ram_total(void);
  57. static const char *run_command(const char *cmd);
  58. static const char *swap_free(void);
  59. static const char *swap_perc(void);
  60. static const char *swap_used(void);
  61. static const char *swap_total(void);
  62. static const char *temp(const char *file);
  63. static const char *uid(void);
  64. static const char *uptime(void);
  65. static const char *username(void);
  66. static const char *vol_perc(const char *card);
  67. static const char *wifi_perc(const char *iface);
  68. static const char *wifi_essid(const char *iface);
  69. char *argv0;
  70. static unsigned short int done;
  71. static Display *dpy;
  72. #include "config.h"
  73. static char buf[MAXLEN];
  74. static const char *
  75. bprintf(const char *fmt, ...)
  76. {
  77. va_list ap;
  78. size_t len;
  79. va_start(ap, fmt);
  80. len = vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
  81. va_end(ap);
  82. if (len >= sizeof(buf))
  83. buf[sizeof(buf)-1] = '\0';
  84. return buf;
  85. }
  86. int
  87. pscanf(const char *path, const char *fmt, ...)
  88. {
  89. FILE *fp;
  90. va_list ap;
  91. int n;
  92. if (!(fp = fopen(path, "r"))) {
  93. warn("fopen %s: %s\n", path, strerror(errno));
  94. return -1;
  95. }
  96. va_start(ap, fmt);
  97. n = vfscanf(fp, fmt, ap);
  98. va_end(ap);
  99. fclose(fp);
  100. return (n == EOF) ? -1 : n;
  101. }
  102. static const char *
  103. battery_perc(const char *bat)
  104. {
  105. int perc;
  106. char path[PATH_MAX];
  107. snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/capacity");
  108. return (pscanf(path, "%i", &perc) == 1) ?
  109. bprintf("%d", perc) : unknown_str;
  110. }
  111. static const char *
  112. battery_power(const char *bat)
  113. {
  114. int watts;
  115. char path[PATH_MAX];
  116. snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/power_now");
  117. return (pscanf(path, "%i", &watts) == 1) ?
  118. bprintf("%d", (watts + 500000) / 1000000) : unknown_str;
  119. }
  120. static const char *
  121. battery_state(const char *bat)
  122. {
  123. struct {
  124. char *state;
  125. char *symbol;
  126. } map[] = {
  127. { "Charging", "+" },
  128. { "Discharging", "-" },
  129. { "Full", "=" },
  130. { "Unknown", "/" },
  131. };
  132. size_t i;
  133. char path[PATH_MAX], state[12];
  134. snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/status");
  135. if (pscanf(path, "%12s", state) != 1) {
  136. return unknown_str;
  137. }
  138. for (i = 0; i < LEN(map); i++) {
  139. if (!strcmp(map[i].state, state)) {
  140. break;
  141. }
  142. }
  143. return (i == LEN(map)) ? "?" : map[i].symbol;
  144. }
  145. static const char *
  146. cpu_freq(void)
  147. {
  148. int freq;
  149. return (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
  150. "%i", &freq) == 1) ?
  151. bprintf("%d", (freq + 500) / 1000) : unknown_str;
  152. }
  153. static const char *
  154. cpu_perc(void)
  155. {
  156. struct timespec delay;
  157. int perc;
  158. long double a[4], b[4];
  159. if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2],
  160. &a[3]) != 4) {
  161. return unknown_str;
  162. }
  163. delay.tv_sec = (interval / 2) / 1000;
  164. delay.tv_nsec = ((interval / 2) % 1000) * 1000000;
  165. nanosleep(&delay, NULL);
  166. if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2],
  167. &b[3]) != 4) {
  168. return unknown_str;
  169. }
  170. perc = 100 * ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) /
  171. ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3]));
  172. return bprintf("%d", perc);
  173. }
  174. static const char *
  175. datetime(const char *fmt)
  176. {
  177. time_t t;
  178. t = time(NULL);
  179. if (strftime(buf, sizeof(buf), fmt, localtime(&t)) == 0)
  180. return unknown_str;
  181. return buf;
  182. }
  183. static const char *
  184. disk_free(const char *mnt)
  185. {
  186. struct statvfs fs;
  187. if (statvfs(mnt, &fs) < 0) {
  188. warn("Failed to get filesystem info");
  189. return unknown_str;
  190. }
  191. return bprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
  192. }
  193. static const char *
  194. disk_perc(const char *mnt)
  195. {
  196. int perc;
  197. struct statvfs fs;
  198. if (statvfs(mnt, &fs) < 0) {
  199. warn("Failed to get filesystem info");
  200. return unknown_str;
  201. }
  202. perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
  203. return bprintf("%d", perc);
  204. }
  205. static const char *
  206. disk_total(const char *mnt)
  207. {
  208. struct statvfs fs;
  209. if (statvfs(mnt, &fs) < 0) {
  210. warn("Failed to get filesystem info");
  211. return unknown_str;
  212. }
  213. return bprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
  214. }
  215. static const char *
  216. disk_used(const char *mnt)
  217. {
  218. struct statvfs fs;
  219. if (statvfs(mnt, &fs) < 0) {
  220. warn("Failed to get filesystem info");
  221. return unknown_str;
  222. }
  223. return bprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
  224. }
  225. static const char *
  226. entropy(void)
  227. {
  228. int num;
  229. return (pscanf("/proc/sys/kernel/random/entropy_avail", "%d", &num) == 1) ?
  230. bprintf("%d", num) : unknown_str;
  231. }
  232. static const char *
  233. gid(void)
  234. {
  235. return bprintf("%d", getgid());
  236. }
  237. static const char *
  238. hostname(void)
  239. {
  240. if (gethostname(buf, sizeof(buf)) == -1) {
  241. warn("hostname");
  242. return unknown_str;
  243. }
  244. return buf;
  245. }
  246. static const char *
  247. ipv4(const char *iface)
  248. {
  249. struct ifaddrs *ifaddr, *ifa;
  250. int s;
  251. char host[NI_MAXHOST];
  252. if (getifaddrs(&ifaddr) == -1) {
  253. warn("Failed to get IPv4 address for interface %s", iface);
  254. return unknown_str;
  255. }
  256. for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  257. if (ifa->ifa_addr == NULL) {
  258. continue;
  259. }
  260. s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  261. if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
  262. if (s != 0) {
  263. warnx("Failed to get IPv4 address for interface %s", iface);
  264. return unknown_str;
  265. }
  266. return bprintf("%s", host);
  267. }
  268. }
  269. freeifaddrs(ifaddr);
  270. return unknown_str;
  271. }
  272. static const char *
  273. ipv6(const char *iface)
  274. {
  275. struct ifaddrs *ifaddr, *ifa;
  276. int s;
  277. char host[NI_MAXHOST];
  278. if (getifaddrs(&ifaddr) == -1) {
  279. warn("Failed to get IPv6 address for interface %s", iface);
  280. return unknown_str;
  281. }
  282. for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  283. if (ifa->ifa_addr == NULL) {
  284. continue;
  285. }
  286. s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  287. if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET6)) {
  288. if (s != 0) {
  289. warnx("Failed to get IPv6 address for interface %s", iface);
  290. return unknown_str;
  291. }
  292. return bprintf("%s", host);
  293. }
  294. }
  295. freeifaddrs(ifaddr);
  296. return unknown_str;
  297. }
  298. static const char *
  299. kernel_release(void)
  300. {
  301. struct utsname udata;
  302. if (uname(&udata) < 0) {
  303. return unknown_str;
  304. }
  305. return bprintf("%s", udata.release);
  306. }
  307. static const char *
  308. keyboard_indicators(void)
  309. {
  310. Display *dpy = XOpenDisplay(NULL);
  311. XKeyboardState state;
  312. if (dpy == NULL) {
  313. warnx("XOpenDisplay failed");
  314. return unknown_str;
  315. }
  316. XGetKeyboardControl(dpy, &state);
  317. XCloseDisplay(dpy);
  318. switch (state.led_mask) {
  319. case 1:
  320. return "c";
  321. case 2:
  322. return "n";
  323. case 3:
  324. return "cn";
  325. default:
  326. return "";
  327. }
  328. }
  329. static const char *
  330. load_avg(const char *fmt)
  331. {
  332. double avgs[3];
  333. if (getloadavg(avgs, 3) < 0) {
  334. warnx("Failed to get the load avg");
  335. return unknown_str;
  336. }
  337. return bprintf(fmt, avgs[0], avgs[1], avgs[2]);
  338. }
  339. static const char *
  340. num_files(const char *dir)
  341. {
  342. struct dirent *dp;
  343. DIR *fd;
  344. int num = 0;
  345. if ((fd = opendir(dir)) == NULL) {
  346. warn("Failed to get number of files in directory %s", dir);
  347. return unknown_str;
  348. }
  349. while ((dp = readdir(fd)) != NULL) {
  350. if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  351. continue; /* skip self and parent */
  352. num++;
  353. }
  354. closedir(fd);
  355. return bprintf("%d", num);
  356. }
  357. static const char *
  358. ram_free(void)
  359. {
  360. long free;
  361. return (pscanf("/proc/meminfo", "MemFree: %ld kB\n", &free) == 1) ?
  362. bprintf("%f", (float)free / 1024 / 1024) : unknown_str;
  363. }
  364. static const char *
  365. ram_perc(void)
  366. {
  367. long total, free, buffers, cached;
  368. return (pscanf("/proc/meminfo",
  369. "MemTotal: %ld kB\n"
  370. "MemFree: %ld kB\n"
  371. "MemAvailable: %ld kB\nBuffers: %ld kB\n"
  372. "Cached: %ld kB\n",
  373. &total, &free, &buffers, &buffers, &cached) == 5) ?
  374. bprintf("%d", 100 * ((total - free) - (buffers + cached)) / total) :
  375. unknown_str;
  376. }
  377. static const char *
  378. ram_total(void)
  379. {
  380. long total;
  381. return (pscanf("/proc/meminfo", "MemTotal: %ld kB\n", &total) == 1) ?
  382. bprintf("%f", (float)total / 1024 / 1024) : unknown_str;
  383. }
  384. static const char *
  385. ram_used(void)
  386. {
  387. long total, free, buffers, cached;
  388. return (pscanf("/proc/meminfo",
  389. "MemTotal: %ld kB\n"
  390. "MemFree: %ld kB\n"
  391. "MemAvailable: %ld kB\nBuffers: %ld kB\n"
  392. "Cached: %ld kB\n",
  393. &total, &free, &buffers, &buffers, &cached) == 5) ?
  394. bprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024) :
  395. unknown_str;
  396. }
  397. static const char *
  398. run_command(const char *cmd)
  399. {
  400. char *p;
  401. FILE *fp;
  402. fp = popen(cmd, "r");
  403. if (fp == NULL) {
  404. warn("Failed to get command output for %s", cmd);
  405. return unknown_str;
  406. }
  407. p = fgets(buf, sizeof(buf) - 1, fp);
  408. pclose(fp);
  409. if (!p)
  410. return unknown_str;
  411. if ((p = strrchr(buf, '\n')) != NULL)
  412. p[0] = '\0';
  413. return buf[0] ? buf : unknown_str;
  414. }
  415. static const char *
  416. swap_free(void)
  417. {
  418. long total, free;
  419. FILE *fp;
  420. size_t bytes_read;
  421. char *match;
  422. fp = fopen("/proc/meminfo", "r");
  423. if (fp == NULL) {
  424. warn("Failed to open file /proc/meminfo");
  425. return unknown_str;
  426. }
  427. if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
  428. warn("swap_free: read error");
  429. fclose(fp);
  430. return unknown_str;
  431. }
  432. fclose(fp);
  433. if ((match = strstr(buf, "SwapTotal")) == NULL)
  434. return unknown_str;
  435. sscanf(match, "SwapTotal: %ld kB\n", &total);
  436. if ((match = strstr(buf, "SwapFree")) == NULL)
  437. return unknown_str;
  438. sscanf(match, "SwapFree: %ld kB\n", &free);
  439. return bprintf("%f", (float)free / 1024 / 1024);
  440. }
  441. static const char *
  442. swap_perc(void)
  443. {
  444. long total, free, cached;
  445. FILE *fp;
  446. size_t bytes_read;
  447. char *match;
  448. fp = fopen("/proc/meminfo", "r");
  449. if (fp == NULL) {
  450. warn("Failed to open file /proc/meminfo");
  451. return unknown_str;
  452. }
  453. if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
  454. warn("swap_perc: read error");
  455. fclose(fp);
  456. return unknown_str;
  457. }
  458. fclose(fp);
  459. if ((match = strstr(buf, "SwapTotal")) == NULL)
  460. return unknown_str;
  461. sscanf(match, "SwapTotal: %ld kB\n", &total);
  462. if ((match = strstr(buf, "SwapCached")) == NULL)
  463. return unknown_str;
  464. sscanf(match, "SwapCached: %ld kB\n", &cached);
  465. if ((match = strstr(buf, "SwapFree")) == NULL)
  466. return unknown_str;
  467. sscanf(match, "SwapFree: %ld kB\n", &free);
  468. return bprintf("%d", 100 * (total - free - cached) / total);
  469. }
  470. static const char *
  471. swap_total(void)
  472. {
  473. long total;
  474. FILE *fp;
  475. size_t bytes_read;
  476. char *match;
  477. fp = fopen("/proc/meminfo", "r");
  478. if (fp == NULL) {
  479. warn("Failed to open file /proc/meminfo");
  480. return unknown_str;
  481. }
  482. if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
  483. warn("swap_total: read error");
  484. fclose(fp);
  485. return unknown_str;
  486. }
  487. fclose(fp);
  488. if ((match = strstr(buf, "SwapTotal")) == NULL)
  489. return unknown_str;
  490. sscanf(match, "SwapTotal: %ld kB\n", &total);
  491. return bprintf("%f", (float)total / 1024 / 1024);
  492. }
  493. static const char *
  494. swap_used(void)
  495. {
  496. long total, free, cached;
  497. FILE *fp;
  498. size_t bytes_read;
  499. char *match;
  500. fp = fopen("/proc/meminfo", "r");
  501. if (fp == NULL) {
  502. warn("Failed to open file /proc/meminfo");
  503. return unknown_str;
  504. }
  505. if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
  506. warn("swap_used: read error");
  507. fclose(fp);
  508. return unknown_str;
  509. }
  510. fclose(fp);
  511. if ((match = strstr(buf, "SwapTotal")) == NULL)
  512. return unknown_str;
  513. sscanf(match, "SwapTotal: %ld kB\n", &total);
  514. if ((match = strstr(buf, "SwapCached")) == NULL)
  515. return unknown_str;
  516. sscanf(match, "SwapCached: %ld kB\n", &cached);
  517. if ((match = strstr(buf, "SwapFree")) == NULL)
  518. return unknown_str;
  519. sscanf(match, "SwapFree: %ld kB\n", &free);
  520. return bprintf("%f", (float)(total - free - cached) / 1024 / 1024);
  521. }
  522. static const char *
  523. temp(const char *file)
  524. {
  525. int temp;
  526. return (pscanf(file, "%d", &temp) == 1) ?
  527. bprintf("%d", temp / 1000) : unknown_str;
  528. }
  529. static const char *
  530. uptime(void)
  531. {
  532. struct sysinfo info;
  533. int h = 0;
  534. int m = 0;
  535. sysinfo(&info);
  536. h = info.uptime / 3600;
  537. m = (info.uptime - h * 3600 ) / 60;
  538. return bprintf("%dh %dm", h, m);
  539. }
  540. static const char *
  541. username(void)
  542. {
  543. struct passwd *pw = getpwuid(geteuid());
  544. if (pw == NULL) {
  545. warn("Failed to get username");
  546. return unknown_str;
  547. }
  548. return bprintf("%s", pw->pw_name);
  549. }
  550. static const char *
  551. uid(void)
  552. {
  553. return bprintf("%d", geteuid());
  554. }
  555. static const char *
  556. vol_perc(const char *card)
  557. {
  558. unsigned int i;
  559. int v, afd, devmask;
  560. char *vnames[] = SOUND_DEVICE_NAMES;
  561. afd = open(card, O_RDONLY | O_NONBLOCK);
  562. if (afd == -1) {
  563. warn("Cannot open %s", card);
  564. return unknown_str;
  565. }
  566. if (ioctl(afd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
  567. warn("Cannot get volume for %s", card);
  568. close(afd);
  569. return unknown_str;
  570. }
  571. for (i = 0; i < LEN(vnames); i++) {
  572. if (devmask & (1 << i) && !strcmp("vol", vnames[i])) {
  573. if (ioctl(afd, MIXER_READ(i), &v) == -1) {
  574. warn("vol_perc: ioctl");
  575. close(afd);
  576. return unknown_str;
  577. }
  578. }
  579. }
  580. close(afd);
  581. return bprintf("%d", v & 0xff);
  582. }
  583. static const char *
  584. wifi_perc(const char *iface)
  585. {
  586. int i, perc;
  587. char *p, *datastart;
  588. char path[PATH_MAX];
  589. char status[5];
  590. FILE *fp;
  591. snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface, "/operstate");
  592. fp = fopen(path, "r");
  593. if (fp == NULL) {
  594. warn("Failed to open file %s", path);
  595. return unknown_str;
  596. }
  597. p = fgets(status, 5, fp);
  598. fclose(fp);
  599. if(!p || strcmp(status, "up\n") != 0) {
  600. return unknown_str;
  601. }
  602. fp = fopen("/proc/net/wireless", "r");
  603. if (fp == NULL) {
  604. warn("Failed to open file /proc/net/wireless");
  605. return unknown_str;
  606. }
  607. for (i = 0; i < 3; i++) {
  608. if (!(p = fgets(buf, sizeof(buf) - 1, fp)))
  609. break;
  610. }
  611. fclose(fp);
  612. if (i < 2 || !p)
  613. return unknown_str;
  614. if ((datastart = strstr(buf, iface)) == NULL)
  615. return unknown_str;
  616. datastart = (datastart+(strlen(iface)+1));
  617. sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
  618. return bprintf("%d", perc);
  619. }
  620. static const char *
  621. wifi_essid(const char *iface)
  622. {
  623. static char id[IW_ESSID_MAX_SIZE+1];
  624. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  625. struct iwreq wreq;
  626. memset(&wreq, 0, sizeof(struct iwreq));
  627. wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
  628. snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
  629. if (sockfd == -1) {
  630. warn("Failed to get ESSID for interface %s", iface);
  631. return unknown_str;
  632. }
  633. wreq.u.essid.pointer = id;
  634. if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
  635. warn("Failed to get ESSID for interface %s", iface);
  636. return unknown_str;
  637. }
  638. close(sockfd);
  639. if (strcmp(id, "") == 0)
  640. return unknown_str;
  641. else
  642. return id;
  643. }
  644. static void
  645. terminate(const int signo)
  646. {
  647. done = 1;
  648. }
  649. static void
  650. difftimespec(struct timespec *res, struct timespec *a, struct timespec *b)
  651. {
  652. res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec);
  653. res->tv_nsec = a->tv_nsec - b->tv_nsec +
  654. (a->tv_nsec < b->tv_nsec) * 1000000000;
  655. }
  656. static void
  657. usage(void)
  658. {
  659. fprintf(stderr, "usage: %s [-s]\n", argv0);
  660. exit(1);
  661. }
  662. int
  663. main(int argc, char *argv[])
  664. {
  665. struct sigaction act;
  666. struct timespec start, current, diff, intspec, wait;
  667. size_t i, len;
  668. int sflag = 0;
  669. char status[MAXLEN];
  670. ARGBEGIN {
  671. case 's':
  672. sflag = 1;
  673. break;
  674. default:
  675. usage();
  676. } ARGEND
  677. if (argc) {
  678. usage();
  679. }
  680. memset(&act, 0, sizeof(act));
  681. act.sa_handler = terminate;
  682. sigaction(SIGINT, &act, NULL);
  683. sigaction(SIGTERM, &act, NULL);
  684. if (!sflag && !(dpy = XOpenDisplay(NULL))) {
  685. fprintf(stderr, "slstatus: cannot open display");
  686. return 1;
  687. }
  688. while (!done) {
  689. clock_gettime(CLOCK_MONOTONIC, &start);
  690. status[0] = '\0';
  691. for (i = len = 0; i < LEN(args); i++) {
  692. len += snprintf(status + len, sizeof(status) - len,
  693. args[i].fmt, args[i].func(args[i].args));
  694. if (len >= sizeof(status)) {
  695. status[sizeof(status) - 1] = '\0';
  696. }
  697. }
  698. if (sflag) {
  699. printf("%s\n", status);
  700. } else {
  701. XStoreName(dpy, DefaultRootWindow(dpy), status);
  702. XSync(dpy, False);
  703. }
  704. if (!done) {
  705. clock_gettime(CLOCK_MONOTONIC, &current);
  706. difftimespec(&diff, &current, &start);
  707. intspec.tv_sec = interval / 1000;
  708. intspec.tv_nsec = (interval % 1000) * 1000000;
  709. difftimespec(&wait, &intspec, &diff);
  710. if (wait.tv_sec >= 0) {
  711. nanosleep(&wait, NULL);
  712. }
  713. }
  714. }
  715. if (!sflag) {
  716. XStoreName(dpy, DefaultRootWindow(dpy), NULL);
  717. XCloseDisplay(dpy);
  718. }
  719. return 0;
  720. }