/* * Copyright (c) 2004 Gunnar Ritter * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source distribution. */ /* Sccsid @(#)utmpx.c 1.13 (gritter) 12/16/07 */ #include #if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \ defined (__UCLIBC__) || defined (__OpenBSD__) || \ defined (__DragonFly__) || \ defined (__APPLE__) && \ (__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_OS_X_VERSION_10_5) #include #include #include #include #include "utmpx.h" static FILE *utfp; static struct utmpx utx; static const char *utmpfile = _PATH_UTMP; static FILE * init(void) { if (utfp == NULL && (utfp = fopen(utmpfile, "r+")) == NULL) if ((utfp = fopen(utmpfile, "r")) == NULL) return NULL; return utfp; } static struct utmpx * utmp2utmpx(struct utmpx *ux, const struct utmp *up) { #ifndef __dietlibc__ memset(ux, 0, sizeof *ux); ux->ut_tv.tv_sec = up->ut_time; memcpy(ux->ut_line, up->ut_line, UT_LINESIZE); memcpy(ux->ut_user, up->ut_name, UT_NAMESIZE); memcpy(ux->ut_host, up->ut_host, UT_HOSTSIZE); if (strcmp(up->ut_line, "~") == 0) ux->ut_type = BOOT_TIME; else if (strcmp(up->ut_line, "|") == 0) ux->ut_type = OLD_TIME; else if (strcmp(up->ut_line, "}") == 0) ux->ut_type = NEW_TIME; else if (*up->ut_name == 0) ux->ut_type = DEAD_PROCESS; else ux->ut_type = USER_PROCESS; #else /* __dietlibc__ */ *ux = *up; #endif /* __dietlibc__ */ return ux; } static struct utmp * utmpx2utmp(struct utmp *up, const struct utmpx *ux) { #ifndef __dietlibc__ memset(up, 0, sizeof *up); up->ut_time = ux->ut_tv.tv_sec; switch (ux->ut_type) { case DEAD_PROCESS: memcpy(up->ut_line, ux->ut_line, UT_LINESIZE); break; default: case EMPTY: case INIT_PROCESS: case LOGIN_PROCESS: case RUN_LVL: case ACCOUNTING: return NULL; case BOOT_TIME: strcpy(up->ut_name, "reboot"); strcpy(up->ut_line, "~"); break; case OLD_TIME: strcpy(up->ut_name, "date"); strcpy(up->ut_line, "|"); break; case NEW_TIME: strcpy(up->ut_name, "date"); strcpy(up->ut_line, "{"); break; case USER_PROCESS: memcpy(up->ut_line, ux->ut_line, UT_LINESIZE); memcpy(up->ut_name, ux->ut_user, UT_NAMESIZE); memcpy(up->ut_host, ux->ut_host, UT_HOSTSIZE); } #else /* __dietlibc__ */ *up = *ux; #endif /* __dietlibc__ */ return up; } struct utmpx * getutxent(void) { static struct utmp zero; struct utmp ut; if (init() == NULL) return NULL; do { if (fread(&ut, sizeof ut, 1, utfp) != 1) return NULL; } while (memcmp(&ut, &zero, sizeof ut) == 0); return utmp2utmpx(&utx, &ut); } struct utmpx * getutxline(const struct utmpx *ux) { struct utmp ut; if (init() == NULL) return NULL; fseek(utfp, 0, SEEK_SET); while (fread(&ut, sizeof ut, 1, utfp) == 1) { utmp2utmpx(&utx, &ut); if ((utx.ut_type == LOGIN_PROCESS || utx.ut_type == USER_PROCESS) && strcmp(ut.ut_line, utx.ut_line) == 0) return &utx; } return NULL; } struct utmpx * getutxid(const struct utmpx *ux) { #ifdef __dietlibc__ struct utmp ut; #endif if (init() == NULL) return NULL; #ifdef __dietlibc__ fseek(utfp, 0, SEEK_SET); while (fread(&ut, sizeof ut, 1, utfp) == 1) { utmp2utmpx(&utx, &ut); switch (ux->ut_type) { case BOOT_TIME: case OLD_TIME: case NEW_TIME: if (ux->ut_type == utx.ut_type) return &utx; break; case INIT_PROCESS: case LOGIN_PROCESS: case USER_PROCESS: case DEAD_PROCESS: if (ux->ut_type == utx.ut_type && ux->ut_id == utx.ut_id) return &utx; break; } } #endif /* __dietlibc__ */ return NULL; } void setutxent(void) { if (init() == NULL) return; fseek(utfp, 0, SEEK_SET); } void endutxent(void) { FILE *fp; if (init() == NULL) return; fp = utfp; utfp = NULL; fclose(fp); } int utmpxname(const char *name) { utmpfile = strdup(name); return 0; } extern struct utmpx * pututxline(const struct utmpx *up) { struct utmp ut; struct utmpx *rp; if (init() == NULL) return NULL; /* * Cannot use getutxid() because there is no id field. Use * the equivalent of getutxline() instead. */ while (fread(&ut, sizeof ut, 1, utfp) == 1) { if (strncmp(ut.ut_line, up->ut_line, UT_LINESIZE) == 0) { fseek(utfp, -sizeof ut, SEEK_CUR); break; } } fflush(utfp); if (utmpx2utmp(&ut, up) == NULL) rp = NULL; else if (fwrite(&ut, sizeof ut, 1, utfp) == 1) { utx = *up; rp = &utx; } else rp = NULL; fflush(utfp); return rp; } extern void updwtmpx(const char *name, const struct utmpx *up) { FILE *fp; if ((fp = fopen(name, "a")) == NULL) return; fwrite(up, sizeof *up, 1, fp); fclose(fp); } #endif /* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __UCLIBC__ || __OpenBSD__ || __DragonFly__ || __APPLE__ */