/* Built-in functions for sysmon. */ #include #include #include #include "action.h" #include "etree.h" #include "funcs.h" #include "global.h" #include "server.h" #include "sysmon.h" #include "window.h" /*************************************************************************/ /* Threshold for re-retreiving information from a server, in milliseconds */ #define RELOAD_THRESH 100 /*************************************************************************/ /*************************************************************************/ static ETree *s_strftime(ETree **args) { static ETree res = {ET_STRING}; static char buf[256]; time_t t; struct tm *tm; t = time(NULL); tm = localtime(&t); strftime(buf, sizeof(buf), etree_eval_s(args[0]), tm); res.u.stringval = buf; return &res; } /*************************************************************************/ static ETree *i_scrwidth(ETree **args) { static ETree res = {ET_INT}; res.u.intval = scrwidth; return &res; } /*************************************************************************/ static ETree *i_scrheight(ETree **args) { static ETree res = {ET_INT}; res.u.intval = scrheight; return &res; } /*************************************************************************/ static ETree *i_winwidth(ETree **args) { static ETree res = {ET_INT}; Window *win; if (args[0]) win = win_find(etree_eval_s(args[0])); else win = current_window; res.u.intval = win ? win->width : 0; return &res; } /*************************************************************************/ static ETree *i_winheight(ETree **args) { static ETree res = {ET_INT}; Window *win; if (args[0]) win = win_find(etree_eval_s(args[0])); else win = current_window; res.u.intval = win ? win->height : 0; return &res; } /*************************************************************************/ static ETree *i_getstate(ETree **args) { static ETree res = {ET_INT}; Action *act; if (args[0]) act = act_find(etree_eval_s(args[0])); else act = current_action; res.u.intval = act ? act->state : 0; return &res; } /*************************************************************************/ static ETree *s_getmessage(ETree **args) { static ETree res = {ET_STRING}; Action *act; if (args[0]) act = act_find(etree_eval_s(args[0])); else act = current_action; res.u.stringval = act ? act->message : ""; return &res; } /*************************************************************************/ static ETree *i_connectstatus(ETree **args) { static ETree res = {ET_INT}; res.u.intval = current_action ? current_action->connectstatus : -1; return &res; } /*************************************************************************/ static ETree *i_connectdelay(ETree **args) { static ETree res = {ET_INT}; res.u.intval = current_action ? current_action->connectdelay : -1; return &res; } /*************************************************************************/ /*************************************************************************/ static ETree *i_active(ETree **args) { static ETree res = {ET_INT}; Server *s; s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } server_conn(s); if (s->sock >= 0) res.u.intval = 1; else res.u.intval = 0; return &res; } /*************************************************************************/ static ETree *i_uptime(ETree **args) { static ETree res = {ET_INT}; Server *s; s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } res.u.intval = s->uptime; return &res; } /*************************************************************************/ static ETree *s_uptime(ETree **args) { static ETree res = {ET_STRING}; static char buf[256]; Server *s; s = server_find(etree_eval_s(args[0])); if (!s) { *buf = 0; res.u.stringval = buf; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } if (!args[1]) { char *end = buf; if (s->uptime >= 86400) end += snprintf(buf, sizeof(buf), "%d day%s, ", s->uptime/86400, s->uptime>=172800 ? "s" : ""); if (s->uptime % 86400 < 3600) snprintf(end, sizeof(buf)-(end-buf), "%d min", (s->uptime%86400) / 60); else snprintf(end, sizeof(buf)-(end-buf), "%2d:%02d", (s->uptime%86400) / 3600, (s->uptime%3600) / 60); } else { char *what = etree_eval_s(args[1]); if (strcasecmp(what, "days") == 0) { if (s->uptime >= 86400) snprintf(buf, sizeof(buf), "%d day%s, ", s->uptime/86400, s->uptime>=172800 ? "s" : ""); else *buf = 0; } else if (strcasecmp(what, "hhmm") == 0) { snprintf(buf, sizeof(buf), "%2d:%02d", (s->uptime%86400) / 3600, (s->uptime%3600) / 60); } else if (strcasecmp(what, "mins") == 0) { if (s->uptime % 86400 < 3600) snprintf(buf, sizeof(buf), "%d min", (s->uptime%86400) / 60); else snprintf(buf, sizeof(buf), "%2d:%02d", (s->uptime%86400) / 3600, (s->uptime%3600) / 60); } else { strcpy(buf, "???"); } } res.u.stringval = buf; return &res; } /*************************************************************************/ static ETree *i_load(ETree **args) { static ETree res = {ET_INT}; Server *s; int which; s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } which = etree_eval_i(args[1]); if (which == 1) res.u.intval = s->load1; else if (which == 5) res.u.intval = s->load5; else if (which == 15) res.u.intval = s->load15; else res.u.intval = -1; return &res; } /*************************************************************************/ static ETree *s_load(ETree **args) { static ETree res = {ET_STRING}; static char buf[256]; Server *s; int which, val; s = server_find(etree_eval_s(args[0])); if (!s) { *buf = 0; res.u.stringval = buf; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } which = etree_eval_i(args[1]); if (which == 1) val = s->load1; else if (which == 5) val = s->load5; else if (which == 15) val = s->load15; else val = -1; if (val < 0) strcpy(buf, "???"); else snprintf(buf, sizeof(buf), "%d.%02d", val/100, val%100); res.u.stringval = buf; return &res; } /*************************************************************************/ static ETree *i_nusers(ETree **args) { static ETree res = {ET_INT}; Server *s; s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } res.u.intval = s->nusers; return &res; } /*************************************************************************/ static ETree *s_nusers(ETree **args) { static ETree res = {ET_STRING}; static char buf[256]; Server *s; s = server_find(etree_eval_s(args[0])); if (!s) { *buf = 0; res.u.stringval = buf; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } if (s->nusers >= 0) snprintf(buf, sizeof(buf), "%d", s->nusers); else strcpy(buf, "???"); res.u.stringval = buf; return &res; } /*************************************************************************/ static ETree *i_nprocs(ETree **args) { static ETree res = {ET_INT}; Server *s; s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } if (tv_diff_milli(NULL, &s->last_uptime_update) >= RELOAD_THRESH) { server_query(s, Q_UPTIME, 0, NULL); gettimeofday(&s->last_uptime_update, NULL); } res.u.intval = s->nprocs; return &res; } /*************************************************************************/ static ETree *i_memory(ETree **args) { static ETree res = {ET_INT}; Server *s; char *what; s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } if (tv_diff_milli(NULL, &s->last_memory_update) >= RELOAD_THRESH) { server_query(s, Q_MEMORY, 0, NULL); gettimeofday(&s->last_memory_update, NULL); } what = etree_eval_s(args[1]); if (strcasecmp(what, "memtotal") == 0) res.u.intval = s->memtotal; else if (strcasecmp(what, "memfree") == 0) res.u.intval = s->memfree; else if (strcasecmp(what, "memused") == 0) res.u.intval = s->memtotal - s->memfree; else if (strcasecmp(what, "shared") == 0) res.u.intval = s->shared; else if (strcasecmp(what, "buffers") == 0) res.u.intval = s->buffers; else if (strcasecmp(what, "cached") == 0) res.u.intval = s->cached; else if (strcasecmp(what, "realfree") == 0) res.u.intval = s->memfree + s->buffers + s->cached; else if (strcasecmp(what, "realused") == 0) res.u.intval = s->memtotal - (s->memfree + s->buffers + s->cached); else if (strcasecmp(what, "swaptotal") == 0) res.u.intval = s->swaptotal; else if (strcasecmp(what, "swapfree") == 0) res.u.intval = s->swapfree; else if (strcasecmp(what, "swapused") == 0) res.u.intval = s->swaptotal - s->swapfree; else res.u.intval = -1; return &res; } /*************************************************************************/ static ETree *i_disk(ETree **args) { static ETree res = {ET_INT}; Server *s; DiskInfo *di; char filesys[256], *what; int val, i; int isblocks = 0; /* Is it a count of blocks? */ s = server_find(etree_eval_s(args[0])); if (!s) { res.u.intval = 0; return &res; } strncpy(filesys, etree_eval_s(args[1]), sizeof(filesys)-1); filesys[sizeof(filesys)-1] = 0; di = NULL; for (i = 0; i < MAX_DISKS; i++) { if (strcmp(s->disks[i].name, filesys) == 0) { di = &s->disks[i]; break; } } if (!di || tv_diff_milli(NULL, &di->last_update) >= RELOAD_THRESH) { ETree tmp, *ptr = &tmp; tmp.type = ET_STRING; tmp.u.stringval = filesys; server_query(s, Q_DISKFREE, 1, &ptr); gettimeofday(&di->last_update, NULL); } for (i = 0; i < MAX_DISKS; i++) { if (strcmp(s->disks[i].name, filesys) == 0) { di = &s->disks[i]; break; } } if (!di) { res.u.intval = 0; return &res; } what = etree_eval_s(args[2]); if (strcasecmp(what, "blocks") == 0) { isblocks = 1; val = di->blocks; } else if (strcasecmp(what, "bused") == 0) { isblocks = 1; val = di->bused; } else if (strcasecmp(what, "bfree") == 0) { isblocks = 1; val = di->blocks - di->bused; } else if (strcasecmp(what, "bfreepct") == 0) { if (di->blocks > 0) val = ((di->blocks - di->bused)*100 + di->blocks/2) / di->blocks; else val = 100; } else if (strcasecmp(what, "breserved") == 0) { isblocks = 1; val = di->bresv; } else if (strcasecmp(what, "userblocks") == 0) { isblocks = 1; if (di->bused > di->blocks - di->bresv) val = di->bused; else val = di->blocks - di->bresv; } else if (strcasecmp(what, "userbfree") == 0) { isblocks = 1; if (di->bused > di->blocks - di->bresv) val = 0; else val = (di->blocks - di->bresv) - di->bused; } else if (strcasecmp(what, "userbfreepct") == 0) { if (di->blocks > 0) { if (di->bused > di->blocks - di->bresv) val = 0; else { int total = di->blocks - di->bresv; val = ((total - di->bused)*100 + total/2) / total; } } else { val = 100; } } else if (strcasecmp(what, "inodes") == 0) { val = di->inodes; } else if (strcasecmp(what, "iused") == 0) { val = di->iused; } else if (strcasecmp(what, "ifree") == 0) { val = di->inodes - di->iused; } else if (strcasecmp(what, "ifreepct") == 0) { if (di->inodes > 0) val = ((di->inodes - di->iused)*100 + di->inodes/2) / di->inodes; else val = 100; } else if (strcasecmp(what, "ireserved") == 0) { val = di->iresv; } else if (strcasecmp(what, "userinodes") == 0) { if (di->iused > di->inodes - di->iresv) val = di->iused; else val = di->inodes - di->iresv; } else if (strcasecmp(what, "userifree") == 0) { if (di->iused > di->inodes - di->iresv) val = 0; else val = (di->inodes - di->iresv) - di->iused; } else if (strcasecmp(what, "userifreepct") == 0) { if (di->inodes > 0) { if (di->iused > di->inodes - di->iresv) val = 0; else { int total = di->inodes - di->iresv; val = ((total - di->iused)*100 + total/2) / total; } } else { val = 100; } } else { val = -1; } if (isblocks) { if (di->bsize > 1024) val *= di->bsize/1024; else if (di->bsize < 1024 && di->bsize > 0) val /= 1024/di->bsize; } res.u.intval = val; return &res; } /*************************************************************************/ /*************************************************************************/ /* List of functions. */ struct { const char *name; int type; ETree *(*func)(ETree **args); int minargs; int maxargs; int argtypes[8]; } funcs[] = { { "strftime", ET_STRING, s_strftime, 1, 1, {ET_STRING} }, { "scrwidth", ET_INT, i_scrwidth, 0, 0 }, { "scrheight", ET_INT, i_scrheight, 0, 0 }, { "winwidth", ET_INT, i_winwidth, 0, 1, {ET_STRING} }, { "winheight", ET_INT, i_winheight, 0, 1, {ET_STRING} }, { "getstate", ET_INT, i_getstate, 0, 1, {ET_STRING} }, { "getmessage", ET_STRING, s_getmessage, 0, 1, {ET_STRING} }, { "connectstatus",ET_INT, i_connectstatus,0, 0 }, { "connectdelay", ET_INT, i_connectdelay, 0, 0 }, { "active", ET_INT, i_active, 1, 1, {ET_STRING} }, { "uptime", ET_INT, i_uptime, 1, 1, {ET_STRING} }, { "uptime_s", ET_STRING, s_uptime, 1, 2, {ET_STRING,ET_STRING} }, { "load", ET_INT, i_load, 2, 2, {ET_STRING,ET_INT} }, { "load_s", ET_STRING, s_load, 2, 2, {ET_STRING,ET_INT} }, { "nusers", ET_INT, i_nusers, 1, 1, {ET_STRING} }, { "nusers_s", ET_STRING, s_nusers, 1, 1, {ET_STRING} }, { "nprocs", ET_INT, i_nprocs, 1, 1, {ET_STRING} }, { "memory", ET_INT, i_memory, 2, 2, {ET_STRING,ET_STRING} }, { "disk", ET_INT, i_disk, 3, 3, {ET_STRING,ET_STRING,ET_STRING} }, { NULL } }; /*************************************************************************/ /*************************************************************************/ /* External interfaces. */ /*************************************************************************/ /* Return the ID number for a given function name, or -1 if no such * function exists. */ int func_id(const char *name) { int i; for (i = 0; funcs[i].name; i++) { if (strcasecmp(funcs[i].name, name) == 0) return i; } return -1; } /*************************************************************************/ /* Return the type of a given function. */ int func_type(int id) { return funcs[id].type; } /*************************************************************************/ /* Return the minimum number of arguments needed by a given function. */ int func_minargs(int id) { return funcs[id].minargs; } /*************************************************************************/ /* Return the maximum number of arguments needed by a given function. */ int func_maxargs(int id) { return funcs[id].maxargs; } /*************************************************************************/ /* Return the required type of the `arg'th argument, or -1 if there is * either no such argument or no required type for that argument. */ int func_argtype(int id, int arg) { if (arg < 1 || arg > funcs[id].maxargs) return -1; return funcs[id].argtypes[arg-1]; } /*************************************************************************/ /* Return the value of a function. The number and type of arguments is * assumed to be correct. */ ETree *func_eval(int id, ETree **args) { return funcs[id].func(args); } /*************************************************************************/