fix for unaligned access in loggen.c
[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 #ifndef ASSIGN_ANY_LSN_DISK
33 #define ASSIGN_ANY_LSN_DISK(lsn,cycle,block)  \
34     { \
35         INT_SET(((uint *)&(lsn))[0], ARCH_CONVERT, (cycle)); \
36         INT_SET(((uint *)&(lsn))[1], ARCH_CONVERT, (block)); \
37     }
38 #endif
39
40 void
41 usage(void)
42 {
43     fprintf(stderr,"Usage: loggen\n"
44                    "           set up parameters before writing record(s):\n"
45                    "               -f f     - set format\n"
46                    "               -u u     - set uuid\n"
47                    "               -c c     - set cycle\n"
48                    "               -b b     - set block\n"
49                    "               -C c     - set tail cycle\n"
50                    "               -B b     - set tail block\n"
51                    "           write log record(s):\n"
52                    "               -z n     - write n zero block(s)     (1BB)\n"
53                    "               -e n     - write n empty record(s)   (2BB)\n"
54                    "               -m n     - write n unmount record(s) (2BB)\n"
55                    "\n"
56                    "            redirect stdout to external log partition, or pipe to\n"
57                    "            dd with appropriate parameters to stuff into internal log.\n"
58     );
59     exit(1);
60 }
61
62 int         bufblocks            = 0;
63 void        *buf                 = NULL;
64 int         param_cycle          = 1;
65 int         param_block          = 0;
66 int         param_tail_cycle     = 1;
67 int         param_tail_block     = 0;
68 int         param_fmt            = XLOG_FMT;
69 uuid_t      param_uuid           = {0};
70
71 void
72 loggen_alloc(int blocks)
73 {
74     if (!(buf=realloc(buf, blocks*BBSIZE))) {
75         fprintf(stderr,"failed to allocate %d block(s)\n", blocks);
76         exit(1);
77     }
78     memset(buf, 0, blocks*BBSIZE);
79     bufblocks=blocks;
80 }
81
82 void
83 loggen_write(void)
84 {         
85     if (!buf) {
86         fprintf(stderr,"no buffer allocated\n");
87         exit(1);
88     }
89
90     if (fwrite(buf, BBSIZE, bufblocks, stdout) != bufblocks) {
91         perror("fwrite");
92         exit(1);
93     }
94
95 }
96
97 void
98 loggen_zero(int count)
99 {
100     if (!count) count=1;
101     
102     fprintf(stderr,"   *** zero block (1BB) x %d\n", count);
103     loggen_alloc(1);
104     while (count--)
105         loggen_write();
106 }      
107       
108 void
109 loggen_unmount(int count)
110 {
111     xlog_rec_header_t       *head;
112     xlog_op_header_t        *op;
113     /* the data section must be 32 bit size aligned */
114     struct {
115         __uint16_t magic;
116         __uint16_t pad1;
117         __uint32_t pad2; /* may as well make it 64 bits */
118     } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
119     
120     if (!count) count=1;
121     
122     fprintf(stderr,"   *** unmount record (2BB) x %d\n", count);
123     loggen_alloc(2);
124     
125     head = (xlog_rec_header_t *)buf;
126     op   = (xlog_op_header_t  *)(((char*)buf)+BBSIZE);
127
128     /* note that oh_tid actually contains the cycle number
129      * and the tid is stored in h_cycle_data[0] - that's the
130      * way things end up on disk.
131      */
132
133     INT_SET(head->h_magicno,        ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
134     INT_SET(head->h_cycle,          ARCH_CONVERT, param_cycle);
135     INT_SET(head->h_version,        ARCH_CONVERT, 1);
136     INT_SET(head->h_len,            ARCH_CONVERT, 20);
137     INT_SET(head->h_chksum,         ARCH_CONVERT, 0);
138     INT_SET(head->h_prev_block,     ARCH_CONVERT, -1);
139     INT_SET(head->h_num_logops,     ARCH_CONVERT, 1);
140     INT_SET(head->h_cycle_data[0],  ARCH_CONVERT, 0xb0c0d0d0);
141     INT_SET(head->h_fmt,            ARCH_CONVERT, param_fmt);
142     
143     ASSIGN_ANY_LSN_DISK(head->h_tail_lsn, param_tail_cycle, param_tail_block);
144
145     memcpy(head->h_fs_uuid,  param_uuid, sizeof(uuid_t));
146
147     /* now a log unmount op */
148     INT_SET(op->oh_tid,             ARCH_CONVERT, param_cycle);
149     INT_SET(op->oh_len,             ARCH_CONVERT, sizeof(magic));
150     INT_SET(op->oh_clientid,        ARCH_CONVERT, XFS_LOG);
151     INT_SET(op->oh_flags,           ARCH_CONVERT, XLOG_UNMOUNT_TRANS);
152     INT_SET(op->oh_res2,            ARCH_CONVERT, 0);
153
154     /* and the data for this op */
155
156     memcpy(op+1, &magic, sizeof(magic));
157     
158     while (count--) {
159         ASSIGN_ANY_LSN_DISK(head->h_lsn,         
160                 param_cycle, param_block++);
161         
162         loggen_write();
163     }
164
165   
166 void
167 loggen_empty(int count)
168 {
169     xlog_rec_header_t       *head;
170     xlog_op_header_t        *op1, *op2, *op3, *op4, *op5;
171     xfs_trans_header_t      *trans;
172     xfs_buf_log_format_t    blfs;
173     xfs_buf_log_format_t    *blf;
174     int                     *data;
175     char                    *p;
176     
177     if (!count) count=1;
178     
179     fprintf(stderr,"   *** empty record (2BB) x %d\n", count);
180     loggen_alloc(2);
181     
182     p=(char*)buf;
183     head  = (xlog_rec_header_t   *)p;         p+=BBSIZE;
184     op1   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
185     op2   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
186     trans = (xfs_trans_header_t  *)p;         p+=sizeof(xfs_trans_header_t);
187     op3   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
188     blf   = (xfs_buf_log_format_t*)p;         p+=sizeof(xfs_buf_log_format_t);
189     op4   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
190     data  = (int                 *)p;         p+=sizeof(int);
191     op5   = (xlog_op_header_t    *)p;         p+=sizeof(xlog_op_header_t);
192
193     /* note that oh_tid actually contains the cycle number
194      * and the tid is stored in h_cycle_data[0] - that's the
195      * way things end up on disk.
196      */
197
198     INT_SET(head->h_magicno,        ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
199     INT_SET(head->h_cycle,          ARCH_CONVERT, param_cycle);
200     INT_SET(head->h_version,        ARCH_CONVERT, 1);
201     INT_SET(head->h_len,            ARCH_CONVERT, 5*sizeof(xlog_op_header_t) +
202                                                     sizeof(xfs_trans_header_t)+
203                                                     sizeof(xfs_buf_log_format_t)+
204                                                     sizeof(int));
205     INT_SET(head->h_chksum,         ARCH_CONVERT, 0);
206     INT_SET(head->h_prev_block,     ARCH_CONVERT, -1);
207     INT_SET(head->h_num_logops,     ARCH_CONVERT, 5);
208     INT_SET(head->h_cycle_data[0],  ARCH_CONVERT, 0xb0c0d0d0);
209     INT_SET(head->h_fmt,            ARCH_CONVERT, param_fmt);
210     
211     ASSIGN_ANY_LSN_DISK(head->h_tail_lsn,    
212             param_tail_cycle, param_tail_block);
213
214     memcpy(head->h_fs_uuid,  param_uuid, sizeof(uuid_t));
215
216     /* start */
217     INT_SET(op1->oh_tid,            ARCH_CONVERT, 1);
218     INT_SET(op1->oh_len,            ARCH_CONVERT, 0);
219     INT_SET(op1->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
220     INT_SET(op1->oh_flags,          ARCH_CONVERT, XLOG_START_TRANS);
221     INT_SET(op1->oh_res2,           ARCH_CONVERT, 0);
222     /* dummy */
223     INT_SET(op2->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
224     INT_SET(op2->oh_len,            ARCH_CONVERT, sizeof(xfs_trans_header_t));
225     INT_SET(op2->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
226     INT_SET(op2->oh_flags,          ARCH_CONVERT, 0);
227     INT_SET(op2->oh_res2,           ARCH_CONVERT, 0);
228     /* dummy transaction - this stuff doesn't get endian converted */
229     trans->th_magic     = XFS_TRANS_MAGIC;
230     trans->th_type      = XFS_TRANS_DUMMY1;
231     trans->th_tid       = 0;
232     trans->th_num_items = 1;
233     /* buffer */
234     INT_SET(op3->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
235     INT_SET(op3->oh_len,            ARCH_CONVERT, sizeof(xfs_buf_log_format_t));
236     INT_SET(op3->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
237     INT_SET(op3->oh_flags,          ARCH_CONVERT, 0);
238     INT_SET(op3->oh_res2,           ARCH_CONVERT, 0);
239     /* an empty buffer too */
240     blfs.blf_type       = XFS_LI_BUF;
241     blfs.blf_size       = 2;
242     blfs.blf_flags      = XFS_BLI_CANCEL;
243     blfs.blf_blkno      = 1;
244     blfs.blf_map_size   = 1;
245     blfs.blf_data_map[0]= 0;
246     memcpy(blf, &blfs, sizeof(blfs));
247     /* commit */
248     INT_SET(op4->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
249     INT_SET(op4->oh_len,            ARCH_CONVERT, sizeof(int));
250     INT_SET(op4->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
251     INT_SET(op4->oh_flags,          ARCH_CONVERT, 0);
252     INT_SET(op4->oh_res2,           ARCH_CONVERT, 0);
253     /* and the data */
254     *data=*(int*)(char*)"FISH"; /* this won't get written (I hope) */
255     /* commit */
256     INT_SET(op5->oh_tid,            ARCH_CONVERT, 0xb0c0d0d0);
257     INT_SET(op5->oh_len,            ARCH_CONVERT, 0);
258     INT_SET(op5->oh_clientid,       ARCH_CONVERT, XFS_TRANSACTION);
259     INT_SET(op5->oh_flags,          ARCH_CONVERT, XLOG_COMMIT_TRANS);
260     INT_SET(op5->oh_res2,           ARCH_CONVERT, 0);
261
262     while (count--) {
263         ASSIGN_ANY_LSN_DISK(head->h_lsn,         
264                 param_cycle, param_block++);
265         
266         loggen_write();
267     }
268 }   
269
270 int
271 main(int argc, char *argv[])
272 {
273     int c;
274     
275     fprintf(stderr,"*** loggen\n");
276     
277     if (argc<2) usage();
278     
279     while ((c = getopt(argc, argv, "f:u:c:b:C:B:z:e:m:")) != -1) {
280         switch (c) {
281             case 'f':
282                 param_fmt=atoi(optarg);
283                 break;
284             case 'u':
285                 memset(param_uuid, atoi(optarg), sizeof(param_uuid));
286                 break;
287             case 'c':
288                 param_cycle=atoi(optarg);
289                 break;
290             case 'b':
291                 param_block=atoi(optarg);
292                 break;
293             case 'C':
294                 param_tail_cycle=atoi(optarg);
295                 break;
296             case 'B':
297                 param_tail_block=atoi(optarg);
298                 break;
299                 
300             case 'z':
301                 loggen_zero(atoi(optarg));
302                 break;
303             case 'e':
304                 loggen_empty(atoi(optarg));
305                 break;
306             case 'm':
307                 loggen_unmount(atoi(optarg));
308                 break;
309                 
310             default:
311                 fprintf(stderr, "unknown option\n");
312                 usage();
313         }
314     }
315     return 0;   
316 }