summaryrefslogtreecommitdiffstats
path: root/lib/libulog/ulog_getutxent.c
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2009-12-05 19:53:29 +0000
committered <ed@FreeBSD.org>2009-12-05 19:53:29 +0000
commitd48cd1eb37cbd6f11ed810eb81d29ae10112e472 (patch)
tree2ce40e829decaf7f7ede480d55ebd830b6fdd8ec /lib/libulog/ulog_getutxent.c
parent06fcc20479dbea7b80fde60d667c7455ca58c451 (diff)
downloadFreeBSD-src-d48cd1eb37cbd6f11ed810eb81d29ae10112e472.zip
FreeBSD-src-d48cd1eb37cbd6f11ed810eb81d29ae10112e472.tar.gz
Massively extend libulog:
- Just like struct utmp, store strings inside struct utmpx itself. This is needed to make things like pututxline() work. - Add ut_id and ut_pid fields, even though they have little use in our implementation. - It turns out our "reboot" wtmp entries indicate a system boot, so remove REBOOT_TIME - Implement getutxline() and pututxline - Add getutxuser() and setutxfile(), which allows us to crawl wtmp and lastlog files as well. - Add _ULOG_POSIX_NAMES, so we can already use the POSIX names if we really want to.
Diffstat (limited to 'lib/libulog/ulog_getutxent.c')
-rw-r--r--lib/libulog/ulog_getutxent.c273
1 files changed, 238 insertions, 35 deletions
diff --git a/lib/libulog/ulog_getutxent.c b/lib/libulog/ulog_getutxent.c
index 1dd464d..7ffc739 100644
--- a/lib/libulog/ulog_getutxent.c
+++ b/lib/libulog/ulog_getutxent.c
@@ -27,6 +27,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include "ulog_internal.h"
static FILE *ufile;
+static int ufiletype = -1;
void
ulog_endutxent(void)
@@ -44,56 +48,255 @@ ulog_endutxent(void)
ufile = NULL;
}
-struct ulog_utmpx *
-ulog_getutxent(void)
-{
- struct futmp ut;
- static struct ulog_utmpx utx;
+/*
+ * Conversion from on-disk formats to generic ulog_utmpx structure.
+ */
- /* Open the utmp file if not already done so. */
- if (ufile == NULL)
- ulog_setutxent();
- if (ufile == NULL)
- return (NULL);
+static void
+ulog_futmp_to_utmpx(const struct futmp *ut, struct ulog_utmpx *utx)
+{
- if (fread(&ut, sizeof ut, 1, ufile) != 1)
- return (NULL);
-#define COPY_STRING(field) do { \
- free(utx.ut_ ## field); \
- utx.ut_ ## field = strndup(ut.ut_ ## field, \
- sizeof ut.ut_ ## field); \
- if (utx.ut_ ## field == NULL) \
- utx.ut_ ## field = __DECONST(char *, ""); \
+ memset(utx, 0, sizeof *utx);
+#define COPY_STRING(field) do { \
+ strncpy(utx->ut_ ## field, ut->ut_ ## field, \
+ MIN(sizeof utx->ut_ ## field - 1, sizeof ut->ut_ ## field));\
} while (0)
COPY_STRING(user);
COPY_STRING(line);
COPY_STRING(host);
- utx.ut_tv.tv_sec = _time32_to_time(ut.ut_time);
- utx.ut_tv.tv_usec = 0;
-#define MATCH(field, value) (strcmp(utx.ut_ ## field, (value)) == 0)
- if (MATCH(user, "date") && MATCH(line, "|"))
- utx.ut_type = OLD_TIME;
+#undef COPY_STRING
+#define MATCH(field, value) (strcmp(utx->ut_ ## field, (value)) == 0)
+ if (MATCH(user, "reboot") && MATCH(line, "~"))
+ utx->ut_type = BOOT_TIME;
+ else if (MATCH(user, "date") && MATCH(line, "|"))
+ utx->ut_type = OLD_TIME;
else if (MATCH(user, "date") && MATCH(line, "{"))
- utx.ut_type = NEW_TIME;
+ utx->ut_type = NEW_TIME;
else if (MATCH(user, "shutdown") && MATCH(line, "~"))
- utx.ut_type = SHUTDOWN_TIME;
- else if (MATCH(user, "reboot") && MATCH(line, "~"))
- utx.ut_type = REBOOT_TIME;
+ utx->ut_type = SHUTDOWN_TIME;
else if (MATCH(user, "") && MATCH(host, ""))
- utx.ut_type = DEAD_PROCESS;
- else if (!MATCH(user, ""))
- utx.ut_type = USER_PROCESS;
+ utx->ut_type = DEAD_PROCESS;
+ else if (!MATCH(user, "") && !MATCH(line, "") && ut->ut_time != 0)
+ utx->ut_type = USER_PROCESS;
else
- utx.ut_type = EMPTY;
-
+ utx->ut_type = EMPTY;
+ utx->ut_tv.tv_sec = _time32_to_time(ut->ut_time);
+ utx->ut_tv.tv_usec = 0;
+}
+
+static void
+ulog_flastlog_to_utmpx(const struct flastlog *ll, struct ulog_utmpx *utx)
+{
+
+ memset(utx, 0, sizeof *utx);
+#define COPY_STRING(field) do { \
+ strncpy(utx->ut_ ## field, ll->ll_ ## field, \
+ MIN(sizeof utx->ut_ ## field - 1, sizeof ll->ll_ ## field));\
+} while (0)
+ COPY_STRING(line);
+ COPY_STRING(host);
+#undef COPY_STRING
+ if (!MATCH(line, "") && ll->ll_time != 0)
+ utx->ut_type = USER_PROCESS;
+ else
+ utx->ut_type = EMPTY;
+ utx->ut_tv.tv_sec = _time32_to_time(ll->ll_time);
+ utx->ut_tv.tv_usec = 0;
+}
+
+/*
+ * File I/O.
+ */
+
+static inline off_t
+ulog_tell(void)
+{
+
+ if (ufiletype == UTXF_LASTLOG)
+ return (ftello(ufile) / sizeof(struct flastlog));
+ else
+ return (ftello(ufile) / sizeof(struct futmp));
+}
+
+static struct ulog_utmpx *
+ulog_read(off_t off, int whence, int resolve_user)
+{
+ static struct ulog_utmpx utx;
+
+ if (ufile == NULL)
+ ulog_setutxent();
+ if (ufile == NULL)
+ return (NULL);
+
+ /* Only allow seeking to move forward. */
+ if (whence == SEEK_SET && ulog_tell() > off)
+ return (NULL);
+
+ if (ufiletype == UTXF_LASTLOG) {
+ struct flastlog ll;
+ struct passwd *pw = NULL;
+ uid_t uid;
+
+ if (fseeko(ufile, off * sizeof ll, whence) != 0)
+ return (NULL);
+ uid = ulog_tell();
+ if (fread(&ll, sizeof ll, 1, ufile) != 1)
+ return (NULL);
+ ulog_flastlog_to_utmpx(&ll, &utx);
+ if (utx.ut_type == USER_PROCESS && resolve_user)
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ strlcpy(utx.ut_user, pw->pw_name, sizeof utx.ut_user);
+ else
+ sprintf(utx.ut_user, "%u", (unsigned int)uid);
+ } else {
+ struct futmp ut;
+
+ if (fseeko(ufile, off * sizeof(struct futmp), whence) != 0)
+ return (NULL);
+ if (fread(&ut, sizeof ut, 1, ufile) != 1)
+ return (NULL);
+ ulog_futmp_to_utmpx(&ut, &utx);
+ }
return (&utx);
}
-void
-ulog_setutxent(void)
+/*
+ * getutxent().
+ *
+ * Read the next entry from the file.
+ */
+
+struct ulog_utmpx *
+ulog_getutxent(void)
+{
+
+ return ulog_read(0, SEEK_CUR, 1);
+}
+
+/*
+ * ulog_getutxline().
+ *
+ * Read entries from the file, until reaching an entry which matches the
+ * provided TTY device name. We can optimize the case for utmp files,
+ * because they are indexed by TTY device name.
+ */
+
+struct ulog_utmpx *
+ulog_getutxline(const struct ulog_utmpx *line)
{
+ struct ulog_utmpx *utx;
+
+ if (ufile == NULL)
+ ulog_setutxent();
+ if (ufile == NULL)
+ return (NULL);
+
+ if (ufiletype == UTXF_UTMP) {
+ unsigned int slot;
+
+ slot = ulog_ttyslot(line->ut_line);
+ if (slot == 0)
+ return (NULL);
+ utx = ulog_read(slot, SEEK_SET, 1);
+ if (utx->ut_type == USER_PROCESS &&
+ strcmp(utx->ut_line, line->ut_line) == 0)
+ return (utx);
+ return (NULL);
+ } else {
+ for (;;) {
+ utx = ulog_read(0, SEEK_CUR, 1);
+ if (utx == NULL)
+ return (NULL);
+ if (utx->ut_type == USER_PROCESS &&
+ strcmp(utx->ut_line, line->ut_line) == 0)
+ return (utx);
+ }
+ }
+}
+
+/*
+ * ulog_getutxuser().
+ *
+ * Read entries from the file, until reaching an entry which matches the
+ * provided username. We can optimize the case for lastlog files,
+ * because they are indexed by user ID.
+ */
+
+struct ulog_utmpx *
+ulog_getutxuser(const char *user)
+{
+ struct ulog_utmpx *utx;
+
+ if (ufiletype == UTXF_LASTLOG) {
+ struct passwd *pw;
+
+ pw = getpwnam(user);
+ if (pw == NULL)
+ return (NULL);
+ utx = ulog_read(pw->pw_uid, SEEK_SET, 0);
+ if (utx != NULL)
+ strlcpy(utx->ut_user, user, sizeof utx->ut_user);
+ return (utx);
+ } else {
+ for (;;) {
+ utx = ulog_read(0, SEEK_CUR, 1);
+ if (utx == NULL)
+ return (NULL);
+ if (utx->ut_type == USER_PROCESS &&
+ strcmp(utx->ut_user, user) == 0)
+ return (utx);
+ }
+ }
+}
+
+/*
+ * ulog_setutxfile().
+ *
+ * Switch to a different record file. When no filename is provided, the
+ * system default is opened.
+ */
+
+int
+ulog_setutxfile(int type, const char *file)
+{
+
+ /* Supply default files. */
+ switch (type) {
+ case UTXF_UTMP:
+ if (file == NULL)
+ file = _PATH_UTMP;
+ break;
+ case UTXF_WTMP:
+ if (file == NULL)
+ file = _PATH_WTMP;
+ break;
+ case UTXF_LASTLOG:
+ if (file == NULL)
+ file = _PATH_LASTLOG;
+ break;
+ default:
+ return (-1);
+ }
if (ufile != NULL)
fclose(ufile);
- ufile = fopen(_PATH_UTMP, "r");
+ ufile = fopen(file, "r");
+ ufiletype = type;
+ if (ufile == NULL)
+ return (-1);
+ return (0);
+}
+
+/*
+ * ulog_endutxfile().
+ *
+ * Close any opened files.
+ */
+
+void
+ulog_setutxent(void)
+{
+
+ ulog_setutxfile(UTXF_UTMP, NULL);
}
OpenPOWER on IntegriCloud