-/*
- * Reads the configuration from the given file
- *
- */
-static int load_configuration(const char *configfile) {
- #define OPT(x) else if (strcasecmp(dest_name, x) == 0)
-
- /* check if the file exists */
- struct stat buf;
- if (stat(configfile, &buf) < 0)
- return -1;
-
- int result = 0;
- FILE *handle = fopen(configfile, "r");
- if (handle == NULL)
- die("Could not open configfile\n");
- char dest_name[512], dest_value[512], whole_buffer[1026];
-
- while (!feof(handle)) {
- char *ret;
- if ((ret = fgets(whole_buffer, 1024, handle)) == whole_buffer) {
- /* sscanf implicitly strips whitespace */
- if (sscanf(whole_buffer, "%s %[^\n]", dest_name, dest_value) < 1)
- continue;
- } else if (ret != NULL)
- die("Could not read line in configuration file\n");
-
- /* skip comments and empty lines */
- if (dest_name[0] == '#' || strlen(dest_name) < 3)
- continue;
-
- OPT("wlan")
- wlan_interface = strdup(dest_value);
- OPT("eth")
- eth_interface = strdup(dest_value);
- OPT("time_format")
- time_format = strdup(dest_value);
- OPT("battery") {
- struct battery *new = calloc(1, sizeof(struct battery));
- if (new == NULL)
- die("Could not allocate memory\n");
- if (asprintf(&(new->path), "/sys/class/power_supply/BAT%d/uevent", atoi(dest_value)) == -1)
- die("Could not build battery path\n");
-
- /* check if flags were specified for this battery */
- if (strstr(dest_value, ",") != NULL) {
- char *flags = strstr(dest_value, ",");
- flags++;
- if (*flags == 'f')
- new->use_last_full = true;
- }
- SIMPLEQ_INSERT_TAIL(&batteries, new, batteries);
- } OPT("color")
- use_colors = true;
- OPT("get_ethspeed")
- get_ethspeed = true;
- OPT("get_cpu_temperature") {
- get_cpu_temperature = true;
- if (strlen(dest_value) > 0) {
- if (asprintf(&thermal_zone, "/sys/class/thermal/thermal_zone%d/temp", atoi(dest_value)) == -1)
- die("Could not build thermal_zone path\n");
- } else {
- if (asprintf(&thermal_zone, "/sys/class/thermal/thermal_zone0/temp") == -1)
- die("Could not build thermal_zone path\n");
- }
- } OPT("normcolors")
- wmii_normcolors = strdup(dest_value);
- OPT("interval")
- interval = atoi(dest_value);
- OPT("wmii_path")
- {
-#ifndef DZEN
- static glob_t globbuf;
- struct stat stbuf;
- if (glob(dest_value, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0)
- die("glob() failed\n");
- wmii_path = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : dest_value);
- globfree(&globbuf);
-
- if ((stat(wmii_path, &stbuf)) == -1) {
- fprintf(stderr, "Warning: wmii_path contains an invalid path\n");
- free(wmii_path);
- wmii_path = strdup(dest_value);
- }
- if (wmii_path[strlen(wmii_path)-1] != '/')
- die("wmii_path is not terminated by /\n");
-#endif
- }
- OPT("run_watch")
- {
- char *name = strdup(dest_value);
- char *path = name;
- while (*path != ' ')
- path++;
- *(path++) = '\0';
- num_run_watches += 2;
- run_watches = realloc(run_watches, sizeof(char*) * num_run_watches);
- run_watches[num_run_watches-2] = name;
- run_watches[num_run_watches-1] = path;
- }
- OPT("order")
- {
- #define SET_ORDER(opt, idx) { if (strcasecmp(token, opt) == 0) sprintf(order[idx], "%d", c++); }
- char *walk, *token;
- int c = 0;
- walk = token = dest_value;
- while (*walk != '\0') {
- while ((*walk != ',') && (*walk != '\0'))
- walk++;
- *(walk++) = '\0';
- SET_ORDER("run", ORDER_RUN);
- SET_ORDER("wlan", ORDER_WLAN);
- SET_ORDER("eth", ORDER_ETH);
- SET_ORDER("battery", ORDER_BATTERY);
- SET_ORDER("cpu_temperature", ORDER_CPU_TEMPERATURE);
- SET_ORDER("load", ORDER_LOAD);
- SET_ORDER("time", ORDER_TIME);
- token = walk;
- while (isspace((int)(*token)))
- token++;
- }
- }
- else
- {
- result = -2;
- die("Unknown configfile option: %s\n", dest_name);
+int main(int argc, char *argv[]) {
+ unsigned int j;
+
+ cfg_opt_t general_opts[] = {
+ CFG_STR("output_format", "auto", CFGF_NONE),
+ CFG_BOOL("colors", 1, CFGF_NONE),
+ CFG_STR("separator", "default", CFGF_NONE),
+ CFG_STR("color_separator", "#333333", CFGF_NONE),
+ CFG_INT("interval", 1, CFGF_NONE),
+ CFG_COLOR_OPTS("#00FF00", "#FFFF00", "#FF0000"),
+ CFG_STR("markup", "none", CFGF_NONE),
+ CFG_END()};
+
+ cfg_opt_t run_watch_opts[] = {
+ CFG_STR("pidfile", NULL, CFGF_NONE),
+ CFG_STR("format", "%title: %status", CFGF_NONE),
+ CFG_STR("format_down", NULL, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t path_exists_opts[] = {
+ CFG_STR("path", NULL, CFGF_NONE),
+ CFG_STR("format", "%title: %status", CFGF_NONE),
+ CFG_STR("format_down", NULL, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t wireless_opts[] = {
+ CFG_STR("format_up", "W: (%quality at %essid, %bitrate) %ip", CFGF_NONE),
+ CFG_STR("format_down", "W: down", CFGF_NONE),
+ CFG_STR("format_quality", "%3d%s", CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t ethernet_opts[] = {
+ CFG_STR("format_up", "E: %ip (%speed)", CFGF_NONE),
+ CFG_STR("format_down", "E: down", CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t ipv6_opts[] = {
+ CFG_STR("format_up", "%ip", CFGF_NONE),
+ CFG_STR("format_down", "no IPv6", CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t battery_opts[] = {
+ CFG_STR("format", "%status %percentage %remaining", CFGF_NONE),
+ CFG_STR("format_down", "No battery", CFGF_NONE),
+ CFG_STR("status_chr", "CHR", CFGF_NONE),
+ CFG_STR("status_bat", "BAT", CFGF_NONE),
+ CFG_STR("status_unk", "UNK", CFGF_NONE),
+ CFG_STR("status_full", "FULL", CFGF_NONE),
+ CFG_STR("path", "/sys/class/power_supply/BAT%d/uevent", CFGF_NONE),
+ CFG_INT("low_threshold", 30, CFGF_NONE),
+ CFG_STR("threshold_type", "time", CFGF_NONE),
+ CFG_BOOL("last_full_capacity", false, CFGF_NONE),
+ CFG_BOOL("integer_battery_capacity", false, CFGF_NONE),
+ CFG_BOOL("hide_seconds", true, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t time_opts[] = {
+ CFG_STR("format", "%Y-%m-%d %H:%M:%S", CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t tztime_opts[] = {
+ CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
+ CFG_STR("timezone", "", CFGF_NONE),
+ CFG_STR("locale", "", CFGF_NONE),
+ CFG_STR("format_time", NULL, CFGF_NONE),
+ CFG_BOOL("hide_if_equals_localtime", false, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t ddate_opts[] = {
+ CFG_STR("format", "%{%a, %b %d%}, %Y%N - %H", CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t load_opts[] = {
+ CFG_STR("format", "%1min %5min %15min", CFGF_NONE),
+ CFG_STR("format_above_threshold", NULL, CFGF_NONE),
+ CFG_FLOAT("max_threshold", 5, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t memory_opts[] = {
+ CFG_STR("format", "%used %free %available", CFGF_NONE),
+ CFG_STR("format_degraded", NULL, CFGF_NONE),
+ CFG_STR("threshold_degraded", NULL, CFGF_NONE),
+ CFG_STR("threshold_critical", NULL, CFGF_NONE),
+ CFG_STR("memory_used_method", "classical", CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t usage_opts[] = {
+ CFG_STR("format", "%usage", CFGF_NONE),
+ CFG_STR("format_above_threshold", NULL, CFGF_NONE),
+ CFG_STR("format_above_degraded_threshold", NULL, CFGF_NONE),
+ CFG_STR("path", "/proc/stat", CFGF_NONE),
+ CFG_FLOAT("max_threshold", 95, CFGF_NONE),
+ CFG_FLOAT("degraded_threshold", 90, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t temp_opts[] = {
+ CFG_STR("format", "%degrees C", CFGF_NONE),
+ CFG_STR("format_above_threshold", NULL, CFGF_NONE),
+ CFG_STR("path", NULL, CFGF_NONE),
+ CFG_INT("max_threshold", 75, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t disk_opts[] = {
+ CFG_STR("format", "%free", CFGF_NONE),
+ CFG_STR("format_below_threshold", NULL, CFGF_NONE),
+ CFG_STR("format_not_mounted", NULL, CFGF_NONE),
+ CFG_STR("prefix_type", "binary", CFGF_NONE),
+ CFG_STR("threshold_type", "percentage_avail", CFGF_NONE),
+ CFG_FLOAT("low_threshold", 0, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t volume_opts[] = {
+ CFG_STR("format", "♪: %volume", CFGF_NONE),
+ CFG_STR("format_muted", "♪: 0%%", CFGF_NONE),
+ CFG_STR("device", "default", CFGF_NONE),
+ CFG_STR("mixer", "Master", CFGF_NONE),
+ CFG_INT("mixer_idx", 0, CFGF_NONE),
+ CFG_CUSTOM_ALIGN_OPT,
+ CFG_CUSTOM_COLOR_OPTS,
+ CFG_CUSTOM_MIN_WIDTH_OPT,
+ CFG_CUSTOM_SEPARATOR_OPT,
+ CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
+ CFG_END()};
+
+ cfg_opt_t opts[] = {
+ CFG_STR_LIST("order", "{}", CFGF_NONE),
+ CFG_SEC("general", general_opts, CFGF_NONE),
+ CFG_SEC("run_watch", run_watch_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("path_exists", path_exists_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("wireless", wireless_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("ethernet", ethernet_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("battery", battery_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("cpu_temperature", temp_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("disk", disk_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("volume", volume_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("ipv6", ipv6_opts, CFGF_NONE),
+ CFG_SEC("time", time_opts, CFGF_NONE),
+ CFG_SEC("tztime", tztime_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("ddate", ddate_opts, CFGF_NONE),
+ CFG_SEC("load", load_opts, CFGF_NONE),
+ CFG_SEC("memory", memory_opts, CFGF_NONE),
+ CFG_SEC("cpu_usage", usage_opts, CFGF_NONE),
+ CFG_END()};
+
+ char *configfile = NULL;
+ int opt, option_index = 0;
+ struct option long_options[] = {
+ {"config", required_argument, 0, 'c'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {"run-once", no_argument, 0, 0},
+ {0, 0, 0, 0}};
+
+ struct sigaction action;
+ memset(&action, 0, sizeof(struct sigaction));
+ action.sa_handler = fatalsig;
+ main_thread = pthread_self();
+
+ /* Exit upon SIGPIPE because when we have nowhere to write to, gathering system
+ * information is pointless. Also exit explicitly on SIGTERM and SIGINT because
+ * only this will trigger a reset of the cursor in the terminal output-format.
+ */
+ sigaction(SIGPIPE, &action, NULL);
+ sigaction(SIGTERM, &action, NULL);
+ sigaction(SIGINT, &action, NULL);
+
+ memset(&action, 0, sizeof(struct sigaction));
+ action.sa_handler = sigusr1;
+ sigaction(SIGUSR1, &action, NULL);
+
+ if (setlocale(LC_ALL, "") == NULL)
+ die("Could not set locale. Please make sure all your LC_* / LANG settings are correct.");
+
+ while ((opt = getopt_long(argc, argv, "c:hv", long_options, &option_index)) != -1) {
+ switch (opt) {
+ case 'c':
+ configfile = optarg;
+ break;
+ case 'h':
+ printf("i3status " VERSION " © 2008 Michael Stapelberg and contributors\n"
+ "Syntax: %s [-c <configfile>] [-h] [-v]\n",
+ argv[0]);
+ return 0;
+ break;
+ case 'v':
+ printf("i3status " VERSION " © 2008 Michael Stapelberg and contributors\n");
+ return 0;
+ break;
+ case 0:
+ if (strcmp(long_options[option_index].name, "run-once") == 0) {
+ run_once = true;