#include #include #include #include /* list of records of who's logged-in */ typedef struct _urecord_t { char *name; int idle; int count; struct _urecord_t *next; } urecord; void add_urecord(urecord **list, char *n, int i) { if (*list == NULL) { *list = malloc(sizeof(urecord)); asprintf(&((*list)->name), "%s", n); (*list)->idle = i; (*list)->count = 1; (*list)->next = NULL; } else add_urecord(&((*list)->next), n, i); } urecord* find_urecord(urecord *list, char *name) { if (list == NULL) return NULL; else if (strcmp(name, list->name) == 0) return list; else return find_urecord(list->next, name); } const char *getcolor(int i) { static char *green = "00ff00"; static char *lgreen = "00cc00"; static char *yellow = "ffff00"; static char *lyellow = "cccc00"; static char *red1 = "ff0000"; static char *red2 = "cc0000"; static char *red3 = "990000"; static char *red4 = "660000"; if (i == 0) return green; else if (i < 10) return lgreen; else if (i < 20) return yellow; else if (i < 30) return lyellow; else if (i < 40) return red1; else if (i < 50) return red2; else if (i < 60) return red3; else return red4; } void print_urecords(urecord *list) { if (list != NULL) { printf("#%s#%s##%d", getcolor(list->idle), list->name, list->count); if (list->next != NULL) printf(","); print_urecords(list->next); } } int main(int argc, char *argv[]) { char *finger_command; char *buf, *lbuf = NULL; FILE *p; size_t len; int time, hours, minutes, days; char username[255]; char idle[255]; char dummy[255]; urecord *list = NULL; /* ensure proper usage */ if (argc != 2) errx(1, "usage: %s hostname", argv[0]); /* build finger command from provided hostname */ if (asprintf(&finger_command, "/usr/bin/finger @%s", argv[1]) == -1) errx(1, "asprintf fail"); /* fork command and read output */ p = popen(finger_command, "r"); free(finger_command); if (p == NULL) errx(1, "finger failure"); /* start parsing output */ /* discard first two lines */ fgetln(p, &len); fgetln(p, &len); /* start reading user data, if any. note that if the host was invalid, or * there are no users logged in, this simply skips. */ while ((buf = fgetln(p, &len))) { /* zero-end buff (see fgetln(3)) */ if ((buf[len - 1] = '\n')) buf[len - 1] = '\0'; else { if ((lbuf = malloc(len + 1)) == NULL) err(1, NULL); memcpy(lbuf, buf, len); lbuf[len] = '\0'; buf = lbuf; } /* get username */ int offset; if (sscanf(buf, "%s %*20c %*s %n ", username, &offset) != 1) { err(1, "parse fail (username)"); } buf += offset; /* begin long campaign to decipher finger(1) idle format... */ sscanf(buf, "%s", idle); if (idle[0] == '-') { time = 0; } else if (sscanf(buf, "%d%2[ ]", &time, dummy) == 2) { } else if (sscanf(buf, "%dd%2[ ]", &days, dummy) == 2) { time = days * 60 * 24; } else if (sscanf(buf, "%d:%d%*2[ ]", &hours, &minutes) == 2) { time = hours * 60 + minutes; } else if (sscanf(buf, "%d day%d:%d%*2[ ]", &days, &hours, &minutes) == 2) { time = days * 24 * 60 + hours * 60 + minutes; } else if (sscanf(buf, "%d days%d:%d%*2[ ]", &days, &hours, &minutes) == 2) { time = days * 24 * 60 + hours * 60 + minutes; } /* insert/update record */ urecord *location = find_urecord(list, username); if (location == NULL) add_urecord(&list, username, time); else { location->count++; if (time < location->idle) location->idle = time; } if (lbuf != NULL) { free(lbuf); lbuf = NULL; } } print_urecords(list); pclose(p); return 0; }