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.
 
 
 
 

777 lines
16 KiB

  1. /* See LICENSE file for copyright and license details. */
  2. /* global libraries */
  3. #include <alsa/asoundlib.h>
  4. #include <arpa/inet.h>
  5. #include <fcntl.h>
  6. #include <ifaddrs.h>
  7. #include <limits.h>
  8. #include <linux/wireless.h>
  9. #include <locale.h>
  10. #include <netdb.h>
  11. #include <pwd.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/sysinfo.h>
  21. #include <sys/types.h>
  22. #include <time.h>
  23. #include <unistd.h>
  24. #include <X11/Xlib.h>
  25. /* local headers */
  26. #include "slstatus.h"
  27. #include "config.h"
  28. /* set statusbar */
  29. void
  30. setstatus(const char *str)
  31. {
  32. /* set WM_NAME via X11 */
  33. XStoreName(dpy, DefaultRootWindow(dpy), str);
  34. XSync(dpy, False);
  35. }
  36. /* smprintf function */
  37. char *
  38. smprintf(const char *fmt, ...)
  39. {
  40. va_list fmtargs;
  41. char *ret = NULL;
  42. va_start(fmtargs, fmt);
  43. if (vasprintf(&ret, fmt, fmtargs) < 0) {
  44. return NULL;
  45. }
  46. va_end(fmtargs);
  47. return ret;
  48. }
  49. /* battery percentage */
  50. char *
  51. battery_perc(const char *battery)
  52. {
  53. int now, full, perc;
  54. char batterynowfile[64] = "";
  55. char batteryfullfile[64] = "";
  56. FILE *fp;
  57. /* generate battery nowfile path */
  58. strcat(batterynowfile, batterypath);
  59. strcat(batterynowfile, battery);
  60. strcat(batterynowfile, "/");
  61. strcat(batterynowfile, batterynow);
  62. /* generate battery fullfile path */
  63. strcat(batteryfullfile, batterypath);
  64. strcat(batteryfullfile, battery);
  65. strcat(batteryfullfile, "/");
  66. strcat(batteryfullfile, batteryfull);
  67. /* open battery now file */
  68. if (!(fp = fopen(batterynowfile, "r"))) {
  69. fprintf(stderr, "Error opening battery file: %s.\n", batterynowfile);
  70. return smprintf(unknowntext);
  71. }
  72. /* read value */
  73. fscanf(fp, "%i", &now);
  74. /* close battery now file */
  75. fclose(fp);
  76. /* open battery full file */
  77. if (!(fp = fopen(batteryfullfile, "r"))) {
  78. fprintf(stderr, "Error opening battery file.\n");
  79. return smprintf(unknowntext);
  80. }
  81. /* read value */
  82. fscanf(fp, "%i", &full);
  83. /* close battery full file */
  84. fclose(fp);
  85. /* calculate percent */
  86. perc = now / (full / 100);
  87. /* return perc as string */
  88. return smprintf("%d%%", perc);
  89. }
  90. /* cpu percentage */
  91. char *
  92. cpu_perc(const char *null)
  93. {
  94. int perc;
  95. long double a[4], b[4];
  96. FILE *fp;
  97. /* open stat file */
  98. if (!(fp = fopen("/proc/stat","r"))) {
  99. fprintf(stderr, "Error opening stat file.\n");
  100. return smprintf(unknowntext);
  101. }
  102. /* read values */
  103. fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
  104. /* close stat file */
  105. fclose(fp);
  106. /* wait a second (for avg values) */
  107. sleep(1);
  108. /* open stat file */
  109. if (!(fp = fopen("/proc/stat","r"))) {
  110. fprintf(stderr, "Error opening stat file.\n");
  111. return smprintf(unknowntext);
  112. }
  113. /* read values */
  114. fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
  115. /* close stat file */
  116. fclose(fp);
  117. /* calculate avg in this second */
  118. 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]));
  119. /* return perc as string */
  120. return smprintf("%d%%", perc);
  121. }
  122. /* date and time */
  123. char *
  124. datetime(const char *timeformat)
  125. {
  126. time_t tm;
  127. size_t bufsize = 64;
  128. char *buf = malloc(bufsize);
  129. if (buf == NULL) {
  130. fprintf(stderr, "Failed to get date/time.\n");
  131. return smprintf(unknowntext);
  132. }
  133. /* get time in format */
  134. time(&tm);
  135. setlocale(LC_TIME, "");
  136. if (!strftime(buf, bufsize, timeformat, localtime(&tm))) {
  137. setlocale(LC_TIME, "C");
  138. free(buf);
  139. fprintf(stderr, "Strftime failed.\n");
  140. return smprintf(unknowntext);
  141. }
  142. setlocale(LC_TIME, "C");
  143. /* return time */
  144. char *ret = smprintf("%s", buf);
  145. free(buf);
  146. return ret;
  147. }
  148. /* disk free */
  149. char *
  150. disk_free(const char *mountpoint)
  151. {
  152. struct statvfs fs;
  153. /* try to open mountpoint */
  154. if (statvfs(mountpoint, &fs) < 0) {
  155. fprintf(stderr, "Could not get filesystem info.\n");
  156. return smprintf(unknowntext);
  157. }
  158. /* return free */
  159. return smprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
  160. }
  161. /* disk usage percentage */
  162. char *
  163. disk_perc(const char *mountpoint)
  164. {
  165. int perc = 0;
  166. struct statvfs fs;
  167. /* try to open mountpoint */
  168. if (statvfs(mountpoint, &fs) < 0) {
  169. fprintf(stderr, "Could not get filesystem info.\n");
  170. return smprintf(unknowntext);
  171. }
  172. /* calculate percent */
  173. perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
  174. /* return perc */
  175. return smprintf("%d%%", perc);
  176. }
  177. /* disk total */
  178. char *
  179. disk_total(const char *mountpoint)
  180. {
  181. struct statvfs fs;
  182. /* try to open mountpoint */
  183. if (statvfs(mountpoint, &fs) < 0) {
  184. fprintf(stderr, "Could not get filesystem info.\n");
  185. return smprintf(unknowntext);
  186. }
  187. /* return total */
  188. return smprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
  189. }
  190. /* disk used */
  191. char *
  192. disk_used(const char *mountpoint)
  193. {
  194. struct statvfs fs;
  195. /* try to open mountpoint */
  196. if (statvfs(mountpoint, &fs) < 0) {
  197. fprintf(stderr, "Could not get filesystem info.\n");
  198. return smprintf(unknowntext);
  199. }
  200. /* return used */
  201. return smprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
  202. }
  203. /* entropy available */
  204. char *
  205. entropy(const char *null)
  206. {
  207. int entropy = 0;
  208. FILE *fp;
  209. /* open entropy file */
  210. if (!(fp = fopen("/proc/sys/kernel/random/entropy_avail", "r"))) {
  211. fprintf(stderr, "Could not open entropy file.\n");
  212. return smprintf(unknowntext);
  213. }
  214. /* extract entropy */
  215. fscanf(fp, "%d", &entropy);
  216. /* close entropy file */
  217. fclose(fp);
  218. /* return entropy */
  219. return smprintf("%d", entropy);
  220. }
  221. /* gid */
  222. char *
  223. gid(const char *null)
  224. {
  225. gid_t gid;
  226. if ((gid = getgid()) < 0) {
  227. fprintf(stderr, "Could no get gid.\n");
  228. return smprintf(unknowntext);
  229. } else {
  230. return smprintf("%d", gid);
  231. }
  232. return smprintf(unknowntext);
  233. }
  234. /* hostname */
  235. char *
  236. hostname(const char *null)
  237. {
  238. char hostname[HOST_NAME_MAX];
  239. FILE *fp;
  240. /* open hostname file */
  241. if (!(fp = fopen("/proc/sys/kernel/hostname", "r"))) {
  242. fprintf(stderr, "Could not open hostname file.\n");
  243. return smprintf(unknowntext);
  244. }
  245. /* extract hostname */
  246. fscanf(fp, "%s\n", hostname);
  247. /* close hostname file */
  248. fclose(fp);
  249. /* return entropy */
  250. return smprintf("%s", hostname);
  251. }
  252. /* ip address */
  253. char *
  254. ip(const char *interface)
  255. {
  256. struct ifaddrs *ifaddr, *ifa;
  257. int s;
  258. char host[NI_MAXHOST];
  259. /* check if getting ip address works */
  260. if (getifaddrs(&ifaddr) == -1) {
  261. fprintf(stderr, "Error getting IP address.\n");
  262. return smprintf(unknowntext);
  263. }
  264. /* get the ip address */
  265. for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  266. if (ifa->ifa_addr == NULL) {
  267. continue;
  268. }
  269. s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  270. if ((strcmp(ifa->ifa_name, interface) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
  271. if (s != 0) {
  272. fprintf(stderr, "Error getting IP address.\n");
  273. return smprintf(unknowntext);
  274. }
  275. return smprintf("%s", host);
  276. }
  277. }
  278. /* free the address */
  279. freeifaddrs(ifaddr);
  280. return smprintf(unknowntext);
  281. }
  282. /* load avg */
  283. char *
  284. load_avg(const char *null)
  285. {
  286. double avgs[3];
  287. /* try to get load avg */
  288. if (getloadavg(avgs, 3) < 0) {
  289. fprintf(stderr, "Error getting load avg.\n");
  290. return smprintf(unknowntext);
  291. }
  292. /* return it */
  293. return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
  294. }
  295. /* ram free */
  296. char *
  297. ram_free(const char *null)
  298. {
  299. long free;
  300. FILE *fp;
  301. /* open meminfo file */
  302. if (!(fp = fopen("/proc/meminfo", "r"))) {
  303. fprintf(stderr, "Error opening meminfo file.\n");
  304. return smprintf(unknowntext);
  305. }
  306. /* read the values */
  307. fscanf(fp, "MemFree: %ld kB\n", &free);
  308. /* close meminfo file */
  309. fclose(fp);
  310. /* return free ram as string */
  311. return smprintf("%f", (float)free / 1024 / 1024);
  312. }
  313. /* ram percentage */
  314. char *
  315. ram_perc(const char *null)
  316. {
  317. int perc;
  318. long total, free, buffers, cached;
  319. FILE *fp;
  320. /* open meminfo file */
  321. if (!(fp = fopen("/proc/meminfo", "r"))) {
  322. fprintf(stderr, "Error opening meminfo file.\n");
  323. return smprintf(unknowntext);
  324. }
  325. /* read the values */
  326. fscanf(fp, "MemTotal: %ld kB\n", &total);
  327. fscanf(fp, "MemFree: %ld kB\n", &free);
  328. fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
  329. fscanf(fp, "Cached: %ld kB\n", &cached);
  330. /* close meminfo file */
  331. fclose(fp);
  332. /* calculate percentage */
  333. perc = 100 * ((total - free) - (buffers + cached)) / total;
  334. /* return perc as string */
  335. return smprintf("%d%%", perc);
  336. }
  337. /* ram total */
  338. char *
  339. ram_total(const char *null)
  340. {
  341. long total;
  342. FILE *fp;
  343. /* open meminfo file */
  344. if (!(fp = fopen("/proc/meminfo", "r"))) {
  345. fprintf(stderr, "Error opening meminfo file.\n");
  346. return smprintf(unknowntext);
  347. }
  348. /* read the values */
  349. fscanf(fp, "MemTotal: %ld kB\n", &total);
  350. /* close meminfo file */
  351. fclose(fp);
  352. /* return total ram as string */
  353. return smprintf("%f", (float)total / 1024 / 1024);
  354. }
  355. /* ram used */
  356. char *
  357. ram_used(const char *null)
  358. {
  359. long free, total, buffers, cached, used;
  360. FILE *fp;
  361. /* open meminfo file */
  362. if (!(fp = fopen("/proc/meminfo", "r"))) {
  363. fprintf(stderr, "Error opening meminfo file.\n");
  364. return smprintf(unknowntext);
  365. }
  366. /* read the values */
  367. fscanf(fp, "MemTotal: %ld kB\n", &total);
  368. fscanf(fp, "MemFree: %ld kB\n", &free);
  369. fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
  370. fscanf(fp, "Cached: %ld kB\n", &cached);
  371. /* close meminfo file */
  372. fclose(fp);
  373. /* calculate used */
  374. used = total - free - buffers - cached;
  375. /* return used ram as string */
  376. return smprintf("%f", (float)used / 1024 / 1024);
  377. }
  378. /* custom shell command */
  379. char *
  380. run_command(const char* command)
  381. {
  382. int good;
  383. FILE *fp;
  384. char buffer[64];
  385. /* try to open the command output */
  386. if (!(fp = popen(command, "r"))) {
  387. fprintf(stderr, "Could not get command output for: %s.\n", command);
  388. return smprintf(unknowntext);
  389. }
  390. /* get command output text, save it to buffer */
  391. fgets(buffer, sizeof(buffer) - 1, fp);
  392. /* close it again */
  393. pclose(fp);
  394. /* add nullchar at the end */
  395. for (int i = 0 ; i != sizeof(buffer); i++) {
  396. if (buffer[i] == '\0') {
  397. good = 1;
  398. break;
  399. }
  400. }
  401. if (good) {
  402. buffer[strlen(buffer) - 1] = '\0';
  403. }
  404. /* return the output */
  405. return smprintf("%s", buffer);
  406. }
  407. /* temperature */
  408. char *
  409. temp(const char *file)
  410. {
  411. int temperature;
  412. FILE *fp;
  413. /* open temperature file */
  414. if (!(fp = fopen(file, "r"))) {
  415. fprintf(stderr, "Could not open temperature file.\n");
  416. return smprintf(unknowntext);
  417. }
  418. /* extract temperature */
  419. fscanf(fp, "%d", &temperature);
  420. /* close temperature file */
  421. fclose(fp);
  422. /* return temperature in degrees */
  423. return smprintf("%d°C", temperature / 1000);
  424. }
  425. /* uptime */
  426. char *
  427. uptime(const char *null)
  428. {
  429. struct sysinfo info;
  430. int hours = 0;
  431. int minutes = 0;
  432. /* get info */
  433. sysinfo(&info);
  434. hours = info.uptime / 3600;
  435. minutes = (info.uptime - hours * 3600 ) / 60;
  436. /* return it */
  437. return smprintf("%dh %dm", hours, minutes);
  438. }
  439. /* username */
  440. char *
  441. username(const char *null)
  442. {
  443. register struct passwd *pw;
  444. register uid_t uid;
  445. /* get the values */
  446. uid = geteuid();
  447. pw = getpwuid(uid);
  448. /* if it worked, return */
  449. if (pw) {
  450. return smprintf("%s", pw->pw_name);
  451. } else {
  452. fprintf(stderr, "Could not get username.\n");
  453. return smprintf(unknowntext);
  454. }
  455. return smprintf(unknowntext);
  456. }
  457. /* uid */
  458. char *
  459. uid(const char *null)
  460. {
  461. register uid_t uid;
  462. /* get the values */
  463. uid = geteuid();
  464. /* if it worked, return */
  465. if (uid) {
  466. return smprintf("%d", uid);
  467. } else {
  468. fprintf(stderr, "Could not get uid.\n");
  469. return smprintf(unknowntext);
  470. }
  471. return smprintf(unknowntext);
  472. }
  473. /* alsa volume percentage */
  474. char *
  475. vol_perc(const char *soundcard)
  476. {
  477. int mute = 0;
  478. long vol = 0, max = 0, min = 0;
  479. snd_mixer_t *handle;
  480. snd_mixer_elem_t *pcm_mixer, *mas_mixer;
  481. snd_mixer_selem_id_t *vol_info, *mute_info;
  482. /* open everything */
  483. snd_mixer_open(&handle, 0);
  484. snd_mixer_attach(handle, soundcard);
  485. snd_mixer_selem_register(handle, NULL, NULL);
  486. snd_mixer_load(handle);
  487. /* prepare everything */
  488. snd_mixer_selem_id_malloc(&vol_info);
  489. snd_mixer_selem_id_malloc(&mute_info);
  490. /* check */
  491. if (vol_info == NULL || mute_info == NULL) {
  492. fprintf(stderr, "Could not get alsa volume.\n");
  493. return smprintf(unknowntext);
  494. }
  495. snd_mixer_selem_id_set_name(vol_info, channel);
  496. snd_mixer_selem_id_set_name(mute_info, channel);
  497. pcm_mixer = snd_mixer_find_selem(handle, vol_info);
  498. mas_mixer = snd_mixer_find_selem(handle, mute_info);
  499. /* get the info */
  500. snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
  501. snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
  502. snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
  503. /* clean up */
  504. if (vol_info) {
  505. snd_mixer_selem_id_free(vol_info);
  506. }
  507. if (mute_info) {
  508. snd_mixer_selem_id_free(mute_info);
  509. }
  510. if (handle) {
  511. snd_mixer_close(handle);
  512. }
  513. /* return the string (mute) */
  514. if (!mute) {
  515. return smprintf("mute");
  516. } else {
  517. return smprintf("%d%%", (vol * 100) / max);
  518. }
  519. }
  520. /* wifi percentage */
  521. char *
  522. wifi_perc(const char *wificard)
  523. {
  524. int bufsize = 255;
  525. int strength;
  526. char buf[bufsize];
  527. char *datastart;
  528. char path[64];
  529. char status[5];
  530. char needle[sizeof wificard + 1];
  531. FILE *fp;
  532. /* generate the path name */
  533. memset(path, 0, sizeof path);
  534. strcat(path, "/sys/class/net/");
  535. strcat(path, wificard);
  536. strcat(path, "/operstate");
  537. /* open wifi file */
  538. if(!(fp = fopen(path, "r"))) {
  539. fprintf(stderr, "Error opening wifi operstate file.\n");
  540. return smprintf(unknowntext);
  541. }
  542. /* read the status */
  543. fgets(status, 5, fp);
  544. /* close wifi file */
  545. fclose(fp);
  546. /* check if interface down */
  547. if(strcmp(status, "up\n") != 0) {
  548. return smprintf(unknowntext);
  549. }
  550. /* open wifi file */
  551. if (!(fp = fopen("/proc/net/wireless", "r"))) {
  552. fprintf(stderr, "Error opening wireless file.\n");
  553. return smprintf(unknowntext);
  554. }
  555. /* extract the signal strength */
  556. strcpy(needle, wificard);
  557. strcat(needle, ":");
  558. fgets(buf, bufsize, fp);
  559. fgets(buf, bufsize, fp);
  560. fgets(buf, bufsize, fp);
  561. if ((datastart = strstr(buf, needle)) != NULL) {
  562. datastart = strstr(buf, ":");
  563. sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
  564. }
  565. /* close wifi file */
  566. fclose(fp);
  567. /* return strength in percent */
  568. return smprintf("%d%%", strength);
  569. }
  570. /* wifi essid */
  571. char *
  572. wifi_essid(const char *wificard)
  573. {
  574. char id[IW_ESSID_MAX_SIZE+1];
  575. int sockfd;
  576. struct iwreq wreq;
  577. /* prepare */
  578. memset(&wreq, 0, sizeof(struct iwreq));
  579. wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
  580. /* set the interface */
  581. sprintf(wreq.ifr_name, wificard);
  582. /* check */
  583. if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  584. fprintf(stderr, "Cannot open socket for interface: %s\n", wificard);
  585. return smprintf(unknowntext);
  586. }
  587. wreq.u.essid.pointer = id;
  588. if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
  589. fprintf(stderr, "Get ESSID ioctl failed for interface %s\n", wificard);
  590. return smprintf(unknowntext);
  591. }
  592. /* return the essid */
  593. if (strcmp((char *)wreq.u.essid.pointer, "") == 0) {
  594. return smprintf(unknowntext);
  595. } else {
  596. return smprintf("%s", (char *)wreq.u.essid.pointer);
  597. }
  598. }
  599. /* main function */
  600. int
  601. main(void)
  602. {
  603. char status_string[1024];
  604. struct arg argument;
  605. /* try to open display */
  606. if (!(dpy = XOpenDisplay(0x0))) {
  607. fprintf(stderr, "Cannot open display!\n");
  608. exit(1);
  609. }
  610. /* return status every interval */
  611. for (;;) {
  612. /* clear the string */
  613. memset(status_string, 0, sizeof(status_string));
  614. /* generate status_string */
  615. for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
  616. argument = args[i];
  617. char *res = argument.func(argument.args);
  618. char *element = smprintf(argument.format, res);
  619. if (element == NULL) {
  620. element = smprintf(unknowntext);
  621. fprintf(stderr, "Failed to format output.\n");
  622. }
  623. strcat(status_string, element);
  624. free(res);
  625. free(element);
  626. }
  627. /* return the statusbar */
  628. setstatus(status_string);
  629. /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
  630. sleep(update_interval -1);
  631. }
  632. /* close display */
  633. XCloseDisplay(dpy);
  634. /* exit successfully */
  635. return 0;
  636. }