1/*-
2 * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/endian.h>
31#include <sys/param.h>
32
33#include <err.h>
34#include <stdio.h>
35#include <stdint.h>
36#include <stdlib.h>
37#include <string.h>
38#include <utmpx.h>
39
40#include "../../lib/libc/gen/utxdb.h"
41
42struct outmp {
43	char	ut_line[8];
44	char	ut_user[16];
45	char	ut_host[16];
46	int32_t	ut_time;
47};
48
49static void
50usage(void)
51{
52
53	fprintf(stderr, "usage: wtmpcvt input output\n");
54	exit(1);
55}
56
57static void
58outmp_to_futx(const struct outmp *ui, struct futx *uo)
59{
60
61	memset(uo, 0, sizeof *uo);
62#define	COPY_STRING(field) do {						\
63	strncpy(uo->fu_ ## field, ui->ut_ ## field,			\
64	    MIN(sizeof uo->fu_ ## field, sizeof ui->ut_ ## field));	\
65} while (0)
66#define	COPY_LINE_TO_ID() do {						\
67	strncpy(uo->fu_id, ui->ut_line,					\
68	    MIN(sizeof uo->fu_id, sizeof ui->ut_line));			\
69} while (0)
70#define	MATCH(field, value)	(strncmp(ui->ut_ ## field, (value),	\
71					sizeof(ui->ut_ ## field)) == 0)
72	if (MATCH(user, "reboot") && MATCH(line, "~"))
73		uo->fu_type = BOOT_TIME;
74	else if (MATCH(user, "date") && MATCH(line, "|"))
75		uo->fu_type = OLD_TIME;
76	else if (MATCH(user, "date") && MATCH(line, "{"))
77		uo->fu_type = NEW_TIME;
78	else if (MATCH(user, "shutdown") && MATCH(line, "~"))
79		uo->fu_type = SHUTDOWN_TIME;
80	else if (MATCH(user, "") && MATCH(host, "") && !MATCH(line, "")) {
81		uo->fu_type = DEAD_PROCESS;
82		COPY_LINE_TO_ID();
83	} else if (!MATCH(user, "") && !MATCH(line, "") && ui->ut_time != 0) {
84		uo->fu_type = USER_PROCESS;
85		COPY_STRING(user);
86		COPY_STRING(line);
87		COPY_STRING(host);
88		COPY_LINE_TO_ID();
89	} else {
90		uo->fu_type = EMPTY;
91		return;
92	}
93#undef COPY_STRING
94#undef COPY_LINE_TO_ID
95#undef MATCH
96
97	/* Timestamp conversion. XXX: Assumes host byte order! */
98	uo->fu_tv = htobe64((uint64_t)ui->ut_time * 1000000);
99}
100
101int
102main(int argc, char *argv[])
103{
104	FILE *in, *out;
105	struct outmp ui;
106	struct futx uo;
107	size_t l;
108	uint16_t lo;
109
110	if (argc != 3)
111		usage();
112
113	/* Open files. */
114	in = fopen(argv[1], "r");
115	if (in == NULL)
116		err(1, "%s", argv[1]);
117	out = fopen(argv[2], "w");
118	if (out == NULL)
119		err(1, "%s", argv[2]);
120
121	/* Process entries. */
122	while (fread(&ui, sizeof ui, 1, in) == 1) {
123		outmp_to_futx(&ui, &uo);
124		if (uo.fu_type == EMPTY)
125			continue;
126
127		/* Write new entry to output file. */
128		for (l = sizeof uo; l > 0 &&
129		    ((const char *)&uo)[l - 1] == '\0'; l--);
130		lo = htobe16(l);
131		fwrite(&lo, sizeof lo, 1, out);
132		fwrite(&uo, l, 1, out);
133	}
134
135	fclose(in);
136	fclose(out);
137	return (0);
138}
139