4e3bd9aef1e7a147b7e41c71d863dd811b2d681d
[xfstests-dev.git] / src / loggen.c
1 /*
2  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18  
19 /*
20  *
21  * loggen: Generate log entries. Very much incomplete. The empty log
22  *         record is a bit of a misnomer since we need to jump through
23  *         hoops to get a log record that parses ok yet does nothing.
24  *
25  *                                                  - dxm 29/09/00
26  */
27
28 #include <xfs/libxfs.h>
29 #include <xfs/xfs_log.h>
30 #include <xfs/xfs_log_priv.h>
31
32 void
33 usage(void)
34 {
35     fprintf(stderr,"Usage: loggen\n"
36                    "           set up parameters before writing record(s):\n"
37                    "               -f f     - set format\n"
38                    "               -u u     - set uuid\n"
39                    "               -c c     - set cycle\n"
40                    "               -b b     - set block\n"
41                    "               -C c     - set tail cycle\n"
42                    "               -B b     - set tail block\n"
43                    "           write log record(s):\n"
44                    "               -z n     - write n zero block(s)     (1BB)\n"
45                    "               -e n     - write n empty record(s)   (2BB)\n"
46                    "               -m n     - write n unmount record(s) (2BB)\n"
47                    "\n"
48                    "            redirect stdout to external log partition, or pipe to\n"
49                    "            dd with appropriate parameters to stuff into internal log.\n"
50     );
51     exit(1);
52 }
53
54 int         bufblocks            = 0;
55 void        *buf                 = NULL;
56 int         param_cycle          = 1;
57 int         param_block          = 0;
58 int         param_tail_cycle     = 1;
59 int         param_tail_block     = 0;
60 int         param_fmt            = XLOG_FMT;
61 uuid_t      param_uuid           = {0};
62
63 void
64 loggen_alloc(int blocks)
65 {
66     if (!(buf=realloc(buf, blocks*BBSIZE))) {
67         fprintf(stderr,"failed to allocate %d block(s)\n", blocks);
68         exit(1);
69     }
70     memset(buf, 0, blocks*BBSIZE);
71     bufblocks=blocks;
72 }
73
74 void
75 loggen_write(void)
76 {         
77     if (!buf) {
78         fprintf(stderr,"no buffer allocated\n");
79         exit(1);
80     }
81
82     if (fwrite(buf, BBSIZE, bufblocks, stdout) != bufblocks) {
83         perror("fwrite");
84         exit(1);
85     }
86
87 }
88
89 void
90 loggen_zero(int count)
91 {
92     if (!count) count=1;
93     
94     fprintf(stderr,"   *** zero block (1BB) x %d\n", count);
95     loggen_alloc(1);
96     while (count--)
97         loggen_write();
98 }      
99       
100 void
101 loggen_unmount(int count)
102 {
103     xlog_rec_header_t       *head;
104     xlog_op_header_t        *op;
105     /* the data section must be 32 bit size aligned */
106     struct {
107         __uint16_t magic;
108         __uint16_t pad1;
109         __uint32_t pad2; /* may as well make it 64 bits */
110     } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
111     
112     if (!count) count=1;
113     
114     fprintf(stderr,"   *** unmount record (2BB) x %d\n", count);
115     loggen_alloc(2);
116     
117     head = (xlog_rec_header_t *)buf;
118     op   = (xlog_op_header_t  *)(((char*)buf)+BBSIZE);
119
120     /* note that oh_tid actually contains the cycle number
121      * and the tid is stored in h_cycle_data[0] - that's the
122      * way things end up on disk.
123      */
124
125     INT_SET(head->h_magicno,        ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
126     INT_SET(head->h_cycle,          ARCH_CONVERT, param_cycle);
127     INT_SET(head->h_version,        ARCH_CONVERT, 1);
128     INT_SET(head->h_len,            ARCH_CONVERT, 20);
129     INT_SET(head->h_chksum,         ARCH_CONVERT, 0);
130     INT_SET(head->h_prev_block,     ARCH_CONVERT, -1);
131     INT_SET(head->h_num_logops,     ARCH_CONVERT, 1);
132     INT_SET(head->h_cycle_data[0],  ARCH_CONVERT, 0xb0c0d0d0);
133     INT_SET(head->h_fmt,            ARCH_CONVERT, param_fmt);
134     
135     ASSIGN_ANY_LSN_DISK(head->h_tail_lsn, param_tail_cycle, param_tail_block);
136
137     memcpy(head->h_fs_uuid,  param_uuid, sizeof(uuid_t));
138
139     /* now a log unmount op */
140     INT_SET(op->oh_tid,             ARCH_CONVERT, param_cycle);
141     INT_SET(op->oh_len,             ARCH_CONVERT, sizeof(magic));
142     INT_SET(op->oh_clientid,        ARCH_CONVERT, XFS_LOG);
143     INT_SET(op->oh_flags,           ARCH_CONVERT, XLOG_UNMOUNT_TRANS);
144     INT_SET(op->oh_res2,            ARCH_CONVERT, 0);
145
146     /* and the data for this op */
147
148     memcpy(op+1, &magic, sizeof(magic));
149     
150     while (count--) {
151         ASSIGN_ANY_LSN_DISK(head->h_lsn,         
152                 param_cycle, param_block++);
153         
154         loggen_write();
155     }
156
157   
158 void
159 loggen_empty(int count)
160 {
161     xlog_rec_header_t       *head;
162     xlog_op_header_t        *op1, *op2, *op3, *op4, *op5;
163     xfs_trans_header_t      *trans;
164     xfs_buf_log_format_t    *blf;
165     int                     *data;
166     char                    *p;
167     
168     if (!count) count=1;
169     
170     fprintf(stderr,"   *** empty record (2BB) x %d\n", count);
171     loggen_alloc(2);
172     
173     p=(char*)buf;
174     head  = (xlog_rec_header_t   *)p;         p+=BBSIZE;
175     op1   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
176     op2   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
177     trans = (xfs_trans_header_t  *)p;         p+=sizeof(xfs_trans_header_t);
178     op3   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
179     blf   = (xfs_buf_log_format_t*)p;         p+=sizeof(xfs_buf_log_format_t);
180     op4   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
181     data  = (int                 *)p;         p+=sizeof(int);
182     op5   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
183
184     /* note that oh_tid actually contains the cycle number
185      * and the tid is stored in h_cycle_data[0] - that's the
186      * way things end up on disk.
187      */
188
189     INT_SET(head->h_magicno,        ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
190     INT_SET(head->h_cycle,          ARCH_CONVERT, param_cycle);
191     INT_SET(head->h_version,        ARCH_CONVERT, 1);
192     INT_SET(head->h_len,            ARCH_CONVERT, 5*sizeof(xlog_op_header_t) +
193                                                     sizeof(xfs_trans_header_t)+
194                                                     sizeof(xfs_buf_log_format_t)+
195                                                     sizeof(int));
196     INT_SET(head->h_chksum,         ARCH_CONVERT, 0);
197     INT_SET(head->h_prev_block,     ARCH_CONVERT, -1);
198     INT_SET(head->h_num_logops,     ARCH_CONVERT, 5);
199     INT_SET(head->h_cycle_data[0],  ARCH_CONVERT, 0xb0c0d0d0);
200     INT_SET(head->h_fmt,            ARCH_CONVERT, param_fmt);
201     
202     ASSIGN_ANY_LSN_DISK(head->h_tail_lsn,    
203             param_tail_cycle, param_tail_block);
204
205     memcpy(head->h_fs_uuid,  param_uuid, sizeof(uuid_t));
206
207     /* start */
208     INT_SET(op1->oh_tid,            ARCH_CONVERT, 1);
209     INT_SET(op1->oh_len,            ARCH_CONVERT, 0);
210     INT_SET(op1->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
211     INT_SET(op1->oh_flags,          ARCH_CONVERT, XLOG_START_TRANS);
212     INT_SET(op1->oh_res2,           ARCH_CONVERT, 0);
213     /* dummy */
214     INT_SET(op2->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
215     INT_SET(op2->oh_len,            ARCH_CONVERT, sizeof(xfs_trans_header_t));
216     INT_SET(op2->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
217     INT_SET(op2->oh_flags,          ARCH_CONVERT, 0);
218     INT_SET(op2->oh_res2,           ARCH_CONVERT, 0);
219     /* dummy transaction - this stuff doesn't get endian converted */
220     trans->th_magic     = XFS_TRANS_MAGIC;
221     trans->th_type      = XFS_TRANS_DUMMY1;
222     trans->th_tid       = 0;
223     trans->th_num_items = 1;
224     /* buffer */
225     INT_SET(op3->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
226     INT_SET(op3->oh_len,            ARCH_CONVERT, sizeof(xfs_buf_log_format_t));
227     INT_SET(op3->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
228     INT_SET(op3->oh_flags,          ARCH_CONVERT, 0);
229     INT_SET(op3->oh_res2,           ARCH_CONVERT, 0);
230     /* an empty buffer too */
231     blf->blf_type       = XFS_LI_BUF;
232     blf->blf_size       = 2;
233     blf->blf_flags      = XFS_BLI_CANCEL;
234     blf->blf_blkno      = 1;
235     blf->blf_map_size   = 1;
236     blf->blf_data_map[0]= 0;
237     /* commit */
238     INT_SET(op4->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
239     INT_SET(op4->oh_len,            ARCH_CONVERT, sizeof(int));
240     INT_SET(op4->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
241     INT_SET(op4->oh_flags,          ARCH_CONVERT, 0);
242     INT_SET(op4->oh_res2,           ARCH_CONVERT, 0);
243     /* and the data */
244     *data=*(int*)(char*)"FISH"; /* this won't get written (I hope) */
245     /* commit */
246     INT_SET(op5->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
247     INT_SET(op5->oh_len,            ARCH_CONVERT, 0);
248     INT_SET(op5->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
249     INT_SET(op5->oh_flags,          ARCH_CONVERT, XLOG_COMMIT_TRANS);
250     INT_SET(op5->oh_res2,           ARCH_CONVERT, 0);
251
252     while (count--) {
253         ASSIGN_ANY_LSN_DISK(head->h_lsn,         
254                 param_cycle, param_block++);
255         
256         loggen_write();
257     }
258 }   
259
260 int
261 main(int argc, char *argv[])
262 {
263     int c;
264     
265     fprintf(stderr,"*** loggen\n");
266     
267     if (argc<2) usage();
268     
269     while ((c = getopt(argc, argv, "f:u:c:b:C:B:z:e:m:")) != -1) {
270         switch (c) {
271             case 'f':
272                 param_fmt=atoi(optarg);
273                 break;
274             case 'u':
275                 memset(param_uuid, atoi(optarg), sizeof(param_uuid));
276                 break;
277             case 'c':
278                 param_cycle=atoi(optarg);
279                 break;
280             case 'b':
281                 param_block=atoi(optarg);
282                 break;
283             case 'C':
284                 param_tail_cycle=atoi(optarg);
285                 break;
286             case 'B':
287                 param_tail_block=atoi(optarg);
288                 break;
289                 
290             case 'z':
291                 loggen_zero(atoi(optarg));
292                 break;
293             case 'e':
294                 loggen_empty(atoi(optarg));
295                 break;
296             case 'm':
297                 loggen_unmount(atoi(optarg));
298                 break;
299                 
300             default:
301                 fprintf(stderr, "unknown option\n");
302                 usage();
303         }
304     }
305     return 0;   
306 }