My slstatus configuration
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

932 lines
18 KiB

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