/* * Copyright (c) 1989 - 1994, Julianne Frances Haugh * Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 2000 - 2006, Tomasz Kłoczko * Copyright (c) 2007 - 2011, Nicolas François * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the copyright holders or contributors may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Needed for MkLinux DR1/2/2.1 - J. */ #ifndef LASTLOG_FILE #define LASTLOG_FILE "/var/log/lastlog" #endif /* * Global variables */ const char *Prog; /* Program name */ static FILE *lastlogfile; /* lastlog file stream */ static struct stat statbuf; /* fstat buffer for file size */ // TODO just put that in a variable... #define NOW (time ((time_t *) 0)) /* https://gist.github.com/ciembor/1494530 * under the "do what you want :)" license */ float hue2rgb(float p, float q, float t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1./6) return p + (q - p) * 6 * t; if (t < 1./2) return q; if (t < 2./3) return p + (q - p) * (2./3 - t) * 6; return p; } int byteclamp(int n) { if (n < 0) return 0; if (n > 0xFF) return 0xFF; return n; } int hsl2rgb(float h, float s, float l) { float r, g, b; if (0 == s) { r = g = b = l; // achromatic } else { float q = l < 0.5 ? l * (1 + s) : l + s - l * s; float p = 2 * l - q; r = hue2rgb(p, q, h + 1./3) * 255; g = hue2rgb(p, q, h) * 255; b = hue2rgb(p, q, h - 1./3) * 255; } return (byteclamp(r) << 16) + (byteclamp(g) << 8) + byteclamp(b); } static void print_one(const struct passwd *pw) { char *cp; struct tm *tm; time_t ll_time; off_t offset; struct lastlog ll; char ptime[80]; if (NULL == pw) { return; } if (pw->pw_uid < 1000 || pw->pw_uid == 65534) { return; } offset = (off_t) pw->pw_uid * sizeof(ll); if (offset + sizeof(ll) <= statbuf.st_size) { /* fseeko errors are not really relevant for us. */ int err = fseeko(lastlogfile, offset, SEEK_SET); assert(0 == err); /* lastlog is a sparse file. Even if no entries were * entered for this user, which should be able to get the * empty entry in this case. */ if (fread((char *) &ll, sizeof(ll), 1, lastlogfile) != 1) { return; } } else { /* Outsize of the lastlog file. * Behave as if there were a missing entry (same behavior * as if we were reading an non existing entry in the * sparse lastlog file). */ memset(&ll, 0, sizeof(ll)); } ll_time = ll.ll_time; tm = localtime(&ll_time); strftime(ptime, sizeof(ptime), "%a %b %e %H:%M:%S %z %Y", tm); cp = ptime; if (ll.ll_time == (time_t) 0) { cp = "**Never logged in**\0"; } int ago = NOW-ll.ll_time; float f = 1.0 - ((float)ago) / ((float)(60*60*24*365*5)); if (f < 0.0) f = 0.0; f = pow(f, 3.0); float a = 80.0; float b = 2.5; f = MAX(f * f / b, f * a - a + 1.0); float hue = f * 90.0 + 260.; printf("\n", pw->pw_name, hsl2rgb(hue / 360., .2 + f*.7, .1 + f*.9)); } int main(void) { const struct passwd *pwent; lastlogfile = fopen(LASTLOG_FILE, "r"); if (NULL == lastlogfile) { perror(LASTLOG_FILE); exit(EXIT_FAILURE); } /* Get the lastlog size */ if (fstat(fileno(lastlogfile), &statbuf) != 0) { err(1, "can't get lastlog size"); } setpwent(); while ( (pwent = getpwent()) != NULL ) { print_one(pwent); } endpwent(); (void) fclose(lastlogfile); return EXIT_SUCCESS; }