1: /*
2: * $Id: fma_journals.c,v 1.6 2025/04/17 14:34:27 snw Exp $
3: * Journal utilities for fmadm
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
26: * $Log: fma_journals.c,v $
27: * Revision 1.6 2025/04/17 14:34:27 snw
28: * Further logging improvements
29: *
30: * Revision 1.5 2025/04/13 04:22:43 snw
31: * Fix snprintf calls
32: *
33: * Revision 1.4 2025/04/09 19:52:02 snw
34: * Eliminate as many warnings as possible while building with -Wall
35: *
36: * Revision 1.3 2025/03/09 19:14:25 snw
37: * First phase of REUSE compliance and header reformat
38: *
39: *
40: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
41: * SPDX-License-Identifier: AGPL-3.0-or-later
42: **/
43:
44: #include <stdlib.h>
45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <dirent.h>
49: #include <time.h>
50: #include <unistd.h>
51: #include <sys/types.h>
52: #include <sys/stat.h>
53: #include <fcntl.h>
54: #include <errno.h>
55:
56: #include "fmadm.h"
57: #include "jnldefs.h"
58: #include "log.h"
59:
60: void cvt_key (char *buf, char *key);
61: extern short ierr;
62:
63: int fma_journals_examine (int optc, char **opts)
64: {
65: register int i;
66: register int k;
67: int fd;
68: unsigned long siz;
69: unsigned long ct;
70:
71: char buf[2048];
72: char kbuf[1024];
73: char *tbuf;
74:
75: char dbuf[2049];
76:
77: jnl_hdr_t hdr;
78: jnl_ent_t ent;
79:
80: if ((fd = open (fma_journal_path, O_RDONLY)) == -1) {
81: logprintf (FM_LOG_FATAL, "fmadm: error opening journal file %s (error code %ld [%s])",fma_journal_path, errno, strerror (errno));
82: }
83:
84: if (read (fd, &hdr, sizeof (jnl_hdr_t)) == -1) {
85: logprintf (FM_LOG_FATAL, "fmadm: error reading header from journal file %s (error code %ld [%s])", errno, fma_journal_path, strerror (errno));
86: }
87:
88: printf ("\nFreeM Journal Dump\n");
89: printf ("------------------\n\n");
90:
91: printf ("Namespace: %s\n", fma_namespace);
92: printf ("Journal File: %s\n", fma_journal_path);
93: printf ("Journal Format Version: %d\n", hdr.fmt_version);
94: printf ("Cut Threshold: %s bytes\n", fma_journal_cut_threshold);
95:
96: lseek (fd, 0L, SEEK_SET);
97: siz = lseek (fd, 0L, SEEK_END);
98:
99: ct = (siz - sizeof (jnl_hdr_t)) / sizeof (jnl_ent_t);
100:
101: printf ("Journal Entries: %ld\n\n", ct);
102:
103: printf ("%-26s %-6s %-7s %-10s %s\n", "DATE", "PID", "TRNID", "ACTION", "DATA");
104: printf ("%-26s %-6s %-7s %-10s %s\n", "----", "---", "-----", "------", "----");
105:
106: lseek (fd, sizeof (jnl_hdr_t), SEEK_SET);
107:
108: for (i = 0; i < ct; i++) {
109:
110: read (fd, &ent, sizeof (jnl_ent_t));
111:
112: switch (ent.action) {
113:
114: case JNLA_TSTART:
115: strcpy (buf, "TSTART");
116: break;
117:
118: case JNLA_TROLLBACK:
119: strcpy (buf, "TROLLBACK");
120: break;
121:
122: case JNLA_TCOMMIT:
123: strcpy (buf, "TCOMMIT");
124: break;
125:
126: case JNLA_SET:
127: strcpy (buf, "SET");
128: break;
129:
130: case JNLA_KILL:
131: strcpy (buf, "KILL");
132: break;
133:
134: }
135:
136: cvt_key (kbuf, ent.key);
137:
138:
139: tbuf = ctime (&ent.ts);
140: tbuf[strlen(tbuf) - 1] = '\0';
141:
142: if (ent.action == JNLA_SET) {
143:
144: snprintf (dbuf, sizeof (dbuf) - 1, "%s=%s", kbuf, ent.data);
145:
146: for (k = 0; k < strlen (dbuf); k++) {
147: if (dbuf[k] == '\201') dbuf[k] = '\0';
148: }
149:
150: printf ("%-26s %-6d %-7ld %-10s %s\n", tbuf, ent.pid, ent.tran_id, buf, dbuf);
151:
152: }
153: else {
154: printf ("%-26s %-6d %-7ld %-10s %s\n", tbuf, ent.pid, ent.tran_id, buf, kbuf);
155: }
156:
157: }
158:
159: return 0;
160:
161: }
162:
163: int fma_journals_restore (int optc, char **opts)
164: {
165:
166: register int i;
167: int fd;
168: unsigned long siz;
169: unsigned long ct;
170:
171: jnl_hdr_t hdr;
172: jnl_ent_t ent;
173:
174: if ((fd = open (fma_journal_path, O_RDONLY)) == -1) {
175: logprintf (FM_LOG_FATAL, "fmadm: error opening journal file %s (error code %ld [%s])",fma_journal_path, errno, strerror (errno));
176: }
177:
178: if (read (fd, &hdr, sizeof (jnl_hdr_t)) == -1) {
179: logprintf (FM_LOG_FATAL, "fmadm: error reading header from journal file %s (error code %ld [%s])", errno, fma_journal_path, strerror (errno));
180: }
181:
182: printf ("\nFreeM Journal Playback\n");
183: printf ("----------------------\n\n");
184:
185: printf ("Namespace: %s\n", fma_namespace);
186: printf ("Journal File: %s\n", fma_journal_path);
187: printf ("Journal Format Version: %d\n", hdr.fmt_version);
188: printf ("Cut Threshold: %s bytes\n", fma_journal_cut_threshold);
189:
190: lseek (fd, 0L, SEEK_SET);
191: siz = lseek (fd, 0L, SEEK_END);
192:
193: ct = (siz - sizeof (jnl_hdr_t)) / sizeof (jnl_ent_t);
194:
195: printf ("Journal Entries: %ld\n\n", ct);
196:
197:
198: lseek (fd, sizeof (jnl_hdr_t), SEEK_SET);
199:
200: for (i = 0; i < ct; i++) {
201:
202: read (fd, &ent, sizeof (jnl_ent_t));
203:
204: switch (ent.action) {
205:
206: case JNLA_TSTART:
207: printf (" Played back TSTART (transaction id %ld)\n", ent.tran_id);
208: break;
209:
210: case JNLA_TROLLBACK:
211: printf (" Played back TROLLBACK (transaction id %ld)\n", ent.tran_id);
212: break;
213:
214: case JNLA_TCOMMIT:
215: printf (" Played back TCOMMIT (transaction id %ld)\n", ent.tran_id);
216: break;
217:
218: case JNLA_SET:
219: global (set_sym, ent.key, ent.data);
220: printf (" Played back SET (transaction id %ld)\n", ent.tran_id);
221: break;
222:
223: case JNLA_KILL:
224: global (kill_sym, ent.key, ent.data);
225: printf (" Played back KILL (transaction id %ld)\n", ent.tran_id);
226: break;
227:
228: }
229:
230: }
231:
232: return 0;
233:
234: }
235:
236:
237: void cvt_key (char *buf, char *key)
238: {
239: int i;
240: int j = 0;
241: int first = 1;
242:
243: if (key[0] == '\0') {
244: buf[0] = '\0';
245:
246: return;
247: }
248:
249: for(i = 0; i < 1023; i++) {
250:
251: switch (key[i]) {
252:
253: case '\201':
254: if (first == 0) {
255: buf[j] = ')';
256: buf[j + 1] = '\0';
257: }
258: else {
259: buf[j] = '\0';
260: }
261: return;
262:
263: case '\202':
264: if (first == 1) {
265: buf[j] = '(';
266: first = 0;
267: }
268: else {
269: buf[j] = ',';
270: }
271:
272: break;
273:
274: default:
275: buf[j] = key[i];
276: break;
277: }
278:
279: j++;
280: }
281:
282: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>