blob: ed1ebbccc8baa0f8c84f8806225fd2ce4f3ae796 [file] [log] [blame]
/*
* Copyright (c) 2000-2003 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
*
* loggen: Generate log entries. Very much incomplete. The empty log
* record is a bit of a misnomer since we need to jump through
* hoops to get a log record that parses ok yet does nothing.
*
* - dxm 29/09/00
*/
#include <config.h>
#include <xfs/libxfs.h>
#ifdef HAVE_XFS_XFS_LOG_FORMAT_H
#include <xfs/xfs_log_format.h>
#define XFS_TRANS_MAGIC XFS_TRANS_HEADER_MAGIC
#else /* HAVE_XFS_XFS_LOG_FORMAT_H */
#include <xfs/xfs_log.h>
#include <xfs/xfs_log_priv.h>
#endif /* HAVE_XFS_XFS_LOG_FORMAT_H */
#ifndef ASSIGN_ANY_LSN_DISK
#define ASSIGN_ANY_LSN_DISK(lsn,cycle,block) \
{ \
INT_SET(((uint *)&(lsn))[0], ARCH_CONVERT, (cycle)); \
INT_SET(((uint *)&(lsn))[1], ARCH_CONVERT, (block)); \
}
#endif
void
usage(void)
{
fprintf(stderr,"Usage: loggen\n"
" set up parameters before writing record(s):\n"
" -f f - set format\n"
" -u u - set uuid\n"
" -c c - set cycle\n"
" -b b - set block\n"
" -C c - set tail cycle\n"
" -B b - set tail block\n"
" write log record(s):\n"
" -z n - write n zero block(s) (1BB)\n"
" -e n - write n empty record(s) (2BB)\n"
" -m n - write n unmount record(s) (2BB)\n"
"\n"
" redirect stdout to external log partition, or pipe to\n"
" dd with appropriate parameters to stuff into internal log.\n"
);
exit(1);
}
int bufblocks = 0;
void *buf = NULL;
int param_cycle = 1;
int param_block = 0;
int param_tail_cycle = 1;
int param_tail_block = 0;
int param_fmt = XLOG_FMT;
uuid_t param_uuid = {0};
void
loggen_alloc(int blocks)
{
if (!(buf=realloc(buf, blocks*BBSIZE))) {
fprintf(stderr,"failed to allocate %d block(s)\n", blocks);
exit(1);
}
memset(buf, 0, blocks*BBSIZE);
bufblocks=blocks;
}
void
loggen_write(void)
{
if (!buf) {
fprintf(stderr,"no buffer allocated\n");
exit(1);
}
if (fwrite(buf, BBSIZE, bufblocks, stdout) != bufblocks) {
perror("fwrite");
exit(1);
}
}
void
loggen_zero(int count)
{
if (!count) count=1;
fprintf(stderr," *** zero block (1BB) x %d\n", count);
loggen_alloc(1);
while (count--)
loggen_write();
}
void
loggen_unmount(int count)
{
xlog_rec_header_t *head;
xlog_op_header_t *op;
/* the data section must be 32 bit size aligned */
struct {
uint16_t magic;
uint16_t pad1;
uint32_t pad2; /* may as well make it 64 bits */
} magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
if (!count) count=1;
fprintf(stderr," *** unmount record (2BB) x %d\n", count);
loggen_alloc(2);
head = (xlog_rec_header_t *)buf;
op = (xlog_op_header_t *)(((char*)buf)+BBSIZE);
/* note that oh_tid actually contains the cycle number
* and the tid is stored in h_cycle_data[0] - that's the
* way things end up on disk.
*/
head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM);
head->h_cycle = cpu_to_be32(param_cycle);
head->h_version = cpu_to_be32(1);
head->h_len = cpu_to_be32(20);
head->h_prev_block = cpu_to_be32(-1);
head->h_num_logops = cpu_to_be32(1);
head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0);
head->h_fmt = cpu_to_be32(param_fmt);
head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(param_tail_cycle,
param_tail_block));
memcpy(head->h_fs_uuid, param_uuid, sizeof(uuid_t));
/* now a log unmount op */
op->oh_tid = cpu_to_be32(param_cycle);
op->oh_len = cpu_to_be32(sizeof(magic));
op->oh_clientid = XFS_LOG;
op->oh_flags = XLOG_UNMOUNT_TRANS;
op->oh_res2 = cpu_to_be16(0);
/* and the data for this op */
memcpy(op+1, &magic, sizeof(magic));
while (count--) {
head->h_lsn = cpu_to_be64(xlog_assign_lsn(param_cycle, param_block++));
loggen_write();
}
}
void
loggen_empty(int count)
{
xlog_rec_header_t *head;
xlog_op_header_t *op1, *op2, *op3, *op4, *op5;
xfs_trans_header_t *trans;
xfs_buf_log_format_t blfs;
xfs_buf_log_format_t *blf;
int *data;
char *p;
if (!count) count=1;
fprintf(stderr," *** empty record (2BB) x %d\n", count);
loggen_alloc(2);
p=(char*)buf;
head = (xlog_rec_header_t *)p; p+=BBSIZE;
op1 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t);
op2 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t);
trans = (xfs_trans_header_t *)p; p+=sizeof(xfs_trans_header_t);
op3 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t);
blf = (xfs_buf_log_format_t*)p; p+=sizeof(xfs_buf_log_format_t);
op4 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t);
data = (int *)p; p+=sizeof(int);
op5 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t);
/* note that oh_tid actually contains the cycle number
* and the tid is stored in h_cycle_data[0] - that's the
* way things end up on disk.
*/
head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM);
head->h_cycle = cpu_to_be32(param_cycle);
head->h_version = cpu_to_be32(1);
head->h_len = cpu_to_be32(5*sizeof(xlog_op_header_t) +
sizeof(xfs_trans_header_t)+
sizeof(xfs_buf_log_format_t)+
sizeof(int));
head->h_prev_block = cpu_to_be32(-1);
head->h_num_logops = cpu_to_be32(5);
head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0);
head->h_fmt = cpu_to_be32(param_fmt);
head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(param_tail_cycle,
param_tail_block));
memcpy(head->h_fs_uuid, param_uuid, sizeof(uuid_t));
/* start */
op1->oh_tid = cpu_to_be32(1);
op1->oh_len = cpu_to_be32(0);
op1->oh_clientid = XFS_TRANSACTION;
op1->oh_flags = XLOG_START_TRANS;
op1->oh_res2 = cpu_to_be16(0);
/* dummy */
op2->oh_tid = cpu_to_be32(0xb0c0d0d0);
op2->oh_len = cpu_to_be32(sizeof(xfs_trans_header_t));
op2->oh_clientid = XFS_TRANSACTION;
op2->oh_flags = 0;
op2->oh_res2 = cpu_to_be16(0);
/* dummy transaction - this stuff doesn't get endian converted */
trans->th_magic = XFS_TRANS_MAGIC;
trans->th_type = XFS_TRANS_DUMMY1;
trans->th_tid = 0;
trans->th_num_items = 1;
/* buffer */
op3->oh_tid = cpu_to_be32(0xb0c0d0d0);
op3->oh_len = cpu_to_be32(sizeof(xfs_buf_log_format_t));
op3->oh_clientid = XFS_TRANSACTION;
op3->oh_flags = 0;
op3->oh_res2 = cpu_to_be16(0);
/* an empty buffer too */
blfs.blf_type = XFS_LI_BUF;
blfs.blf_size = 2;
#ifdef XFS_BLF_CANCEL
blfs.blf_flags = XFS_BLF_CANCEL;
#else
blfs.blf_flags = XFS_BLI_CANCEL;
#endif
blfs.blf_len = 0;
blfs.blf_blkno = 1;
blfs.blf_map_size = 1;
blfs.blf_data_map[0]= 0;
memcpy(blf, &blfs, sizeof(blfs));
/* commit */
op4->oh_tid = cpu_to_be32(0xb0c0d0d0);
op4->oh_len = cpu_to_be32(sizeof(int));
op4->oh_clientid = XFS_TRANSACTION;
op4->oh_flags = 0;
op4->oh_res2 = cpu_to_be16(0);
/* and the data */
*data=*(int*)(char*)"FISH"; /* this won't get written (I hope) */
/* commit */
op5->oh_tid = cpu_to_be32(0xb0c0d0d0);
op5->oh_len = cpu_to_be32(0);
op5->oh_clientid = XFS_TRANSACTION;
op5->oh_flags = XLOG_COMMIT_TRANS;
op5->oh_res2 = cpu_to_be16(0);
while (count--) {
head->h_lsn = cpu_to_be64(xlog_assign_lsn(param_cycle, param_block++));
loggen_write();
}
}
int
main(int argc, char *argv[])
{
int c;
fprintf(stderr,"*** loggen\n");
if (argc<2) usage();
while ((c = getopt(argc, argv, "f:u:c:b:C:B:z:e:m:")) != -1) {
switch (c) {
case 'f':
param_fmt=atoi(optarg);
break;
case 'u':
memset(param_uuid, atoi(optarg), sizeof(param_uuid));
break;
case 'c':
param_cycle=atoi(optarg);
break;
case 'b':
param_block=atoi(optarg);
break;
case 'C':
param_tail_cycle=atoi(optarg);
break;
case 'B':
param_tail_block=atoi(optarg);
break;
case 'z':
loggen_zero(atoi(optarg));
break;
case 'e':
loggen_empty(atoi(optarg));
break;
case 'm':
loggen_unmount(atoi(optarg));
break;
default:
fprintf(stderr, "unknown option\n");
usage();
}
}
return 0;
}