slstatus.c 17 KB

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