/*
* $Id: fma_journals.c,v 1.3 2025/03/09 19:14:25 snw Exp $
* Journal utilities for fmadm
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: fma_journals.c,v $
* Revision 1.3 2025/03/09 19:14:25 snw
* First phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "fmadm.h"
#include "jnldefs.h"
void cvt_key (char *buf, char *key);
extern short ierr;
int fma_journals_examine (int optc, char **opts)
{
register int i;
register int k;
int fd;
unsigned long siz;
unsigned long ct;
char buf[2048];
char kbuf[1024];
char *tbuf;
char dbuf[2049];
jnl_hdr_t hdr;
jnl_ent_t ent;
if ((fd = open (fma_journal_path, O_RDONLY)) == -1) {
fprintf (stderr, "fmadm: error %d opening journal file %s (%s)\n", errno, fma_journal_path, strerror (errno));
exit (2);
}
if (read (fd, &hdr, sizeof (jnl_hdr_t)) == -1) {
fprintf (stderr, "fmadm: error %d reading header from journal file %s (%s)\n", errno, fma_journal_path, strerror (errno));
exit (3);
}
printf ("\nFreeM Journal Dump\n");
printf ("------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Journal File: %s\n", fma_journal_path);
printf ("Journal Format Version: %d\n", hdr.fmt_version);
printf ("Cut Threshold: %s bytes\n", fma_journal_cut_threshold);
lseek (fd, 0L, SEEK_SET);
siz = lseek (fd, 0L, SEEK_END);
ct = (siz - sizeof (jnl_hdr_t)) / sizeof (jnl_ent_t);
printf ("Journal Entries: %ld\n\n", ct);
printf ("%-26s %-6s %-7s %-10s %s\n", "DATE", "PID", "TRNID", "ACTION", "DATA");
printf ("%-26s %-6s %-7s %-10s %s\n", "----", "---", "-----", "------", "----");
lseek (fd, sizeof (jnl_hdr_t), SEEK_SET);
for (i = 0; i < ct; i++) {
read (fd, &ent, sizeof (jnl_ent_t));
switch (ent.action) {
case JNLA_TSTART:
strcpy (buf, "TSTART");
break;
case JNLA_TROLLBACK:
strcpy (buf, "TROLLBACK");
break;
case JNLA_TCOMMIT:
strcpy (buf, "TCOMMIT");
break;
case JNLA_SET:
strcpy (buf, "SET");
break;
case JNLA_KILL:
strcpy (buf, "KILL");
break;
}
cvt_key (kbuf, ent.key);
tbuf = ctime (&ent.ts);
tbuf[strlen(tbuf) - 1] = '\0';
if (ent.action == JNLA_SET) {
snprintf (dbuf, 2049, "%s=%s", kbuf, ent.data);
for (k = 0; k < strlen (dbuf); k++) {
if (dbuf[k] == '\201') dbuf[k] = '\0';
}
printf ("%-26s %-6d %-7ld %-10s %s\n", tbuf, ent.pid, ent.tran_id, buf, dbuf);
}
else {
printf ("%-26s %-6d %-7ld %-10s %s\n", tbuf, ent.pid, ent.tran_id, buf, kbuf);
}
}
return 0;
}
int fma_journals_restore (int optc, char **opts)
{
register int i;
register int k;
int fd;
unsigned long siz;
unsigned long ct;
char kbuf[1024];
char *tbuf;
char dbuf[2049];
jnl_hdr_t hdr;
jnl_ent_t ent;
if ((fd = open (fma_journal_path, O_RDONLY)) == -1) {
fprintf (stderr, "error: error %d opening journal file %s\n", errno, fma_journal_path);
exit (2);
}
if (read (fd, &hdr, sizeof (jnl_hdr_t)) == -1) {
fprintf (stderr, "error: error %d reading header from journal file %s\n", errno, fma_journal_path);
exit (3);
}
printf ("\nFreeM Journal Playback\n");
printf ("----------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Journal File: %s\n", fma_journal_path);
printf ("Journal Format Version: %d\n", hdr.fmt_version);
printf ("Cut Threshold: %s bytes\n", fma_journal_cut_threshold);
lseek (fd, 0L, SEEK_SET);
siz = lseek (fd, 0L, SEEK_END);
ct = (siz - sizeof (jnl_hdr_t)) / sizeof (jnl_ent_t);
printf ("Journal Entries: %ld\n\n", ct);
lseek (fd, sizeof (jnl_hdr_t), SEEK_SET);
for (i = 0; i < ct; i++) {
read (fd, &ent, sizeof (jnl_ent_t));
switch (ent.action) {
case JNLA_TSTART:
printf (" Played back TSTART (transaction id %ld)\n", ent.tran_id);
break;
case JNLA_TROLLBACK:
printf (" Played back TROLLBACK (transaction id %ld)\n", ent.tran_id);
break;
case JNLA_TCOMMIT:
printf (" Played back TCOMMIT (transaction id %ld)\n", ent.tran_id);
break;
case JNLA_SET:
global (set_sym, ent.key, ent.data);
printf (" Played back SET (transaction id %ld)\n", ent.tran_id);
break;
case JNLA_KILL:
global (kill_sym, ent.key, ent.data);
printf (" Played back KILL (transaction id %ld)\n", ent.tran_id);
break;
}
}
return 0;
}
void cvt_key (char *buf, char *key)
{
int i;
int j = 0;
int first = 1;
if (key[0] == '\0') {
buf[0] = '\0';
return;
}
for(i = 0; i < 1023; i++) {
switch (key[i]) {
case '\201':
if (first == 0) {
buf[j] = ')';
buf[j + 1] = '\0';
}
else {
buf[j] = '\0';
}
return;
case '\202':
if (first == 1) {
buf[j] = '(';
first = 0;
}
else {
buf[j] = ',';
}
break;
default:
buf[j] = key[i];
break;
}
j++;
}
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>