Merge from vendor branch GCC:
[dragonfly.git] / sbin / hammer / cmd_mirror.c
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sbin/hammer/cmd_mirror.c,v 1.1 2008/06/26 04:07:57 dillon Exp $
35  */
36
37 #include "hammer.h"
38
39 #define SERIALBUF_SIZE  (512 * 1024)
40
41 static int read_mrecords(int fd, char *buf, u_int size,
42                          hammer_ioc_mrecord_t pickup);
43 static void mirror_usage(int code);
44
45 void
46 hammer_cmd_mirror_read(char **av, int ac)
47 {
48         struct hammer_ioc_mirror_rw mirror;
49         const char *filesystem;
50         char *buf = malloc(SERIALBUF_SIZE);
51         int fd;
52         hammer_tid_t tid;
53
54         if (ac > 2)
55                 mirror_usage(1);
56         filesystem = av[0];
57         tid = 0;
58         if (ac == 2)
59                 tid = strtoull(av[1], NULL, 0);
60
61         bzero(&mirror, sizeof(mirror));
62         hammer_key_beg_init(&mirror.key_beg);
63         hammer_key_end_init(&mirror.key_end);
64
65         fd = open(filesystem, O_RDONLY);
66         if (fd < 0)
67                 err(1, "Unable to open %s", filesystem);
68
69         hammer_get_cycle(&mirror.key_beg);
70
71         mirror.ubuf = buf;
72         mirror.size = SERIALBUF_SIZE;
73         mirror.tid_beg = tid;
74         mirror.tid_end = HAMMER_MAX_TID;
75
76         do {
77                 mirror.count = 0;
78                 if (ioctl(fd, HAMMERIOC_MIRROR_READ, &mirror) < 0) {
79                         fprintf(stderr, "Mirror-read %s failed: %s\n",
80                                 filesystem, strerror(errno));
81                         exit(1);
82                 }
83                 if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) {
84                         fprintf(stderr,
85                                 "Mirror-read %s interrupted by timer at"
86                                 " %016llx %08x\n",
87                                 filesystem,
88                                 mirror.key_cur.obj_id,
89                                 mirror.key_cur.localization);
90                         if (CyclePath)
91                                 hammer_set_cycle(&mirror.key_cur);
92                         exit(0);
93                 }
94                 mirror.key_beg = mirror.key_cur;
95                 if (mirror.count)
96                         write(1, mirror.ubuf, mirror.count);
97         } while (mirror.count != 0);
98
99         if (CyclePath)
100                 hammer_reset_cycle();
101         fprintf(stderr, "Mirror-read %s succeeded\n", filesystem);
102 }
103
104 void
105 hammer_cmd_mirror_write(char **av, int ac)
106 {
107         struct hammer_ioc_mirror_rw mirror;
108         const char *filesystem;
109         char *buf = malloc(SERIALBUF_SIZE);
110         int fd;
111         struct hammer_ioc_mrecord pickup;
112         hammer_tid_t tid;
113
114         if (ac > 2)
115                 mirror_usage(1);
116         filesystem = av[0];
117         tid = 0;
118         if (ac == 2)
119                 tid = strtoull(av[1], NULL, 0);
120
121         bzero(&mirror, sizeof(mirror));
122         hammer_key_beg_init(&mirror.key_beg);
123         hammer_key_end_init(&mirror.key_end);
124
125         fd = open(filesystem, O_RDONLY);
126         if (fd < 0)
127                 err(1, "Unable to open %s", filesystem);
128
129         mirror.ubuf = buf;
130         mirror.size = SERIALBUF_SIZE;
131         mirror.tid_beg = tid;
132         mirror.tid_end = HAMMER_MAX_TID;
133
134         pickup.signature = 0;
135
136         for (;;) {
137                 mirror.count = 0;
138                 mirror.size = read_mrecords(0, buf, SERIALBUF_SIZE, &pickup);
139                 if (mirror.size <= 0)
140                         break;
141                 if (ioctl(fd, HAMMERIOC_MIRROR_WRITE, &mirror) < 0) {
142                         fprintf(stderr, "Mirror-write %s failed: %s\n",
143                                 filesystem, strerror(errno));
144                         exit(1);
145                 }
146                 if (mirror.head.flags & HAMMER_IOC_HEAD_INTR) {
147                         fprintf(stderr,
148                                 "Mirror-write %s interrupted by timer at"
149                                 " %016llx %08x\n",
150                                 filesystem,
151                                 mirror.key_cur.obj_id,
152                                 mirror.key_cur.localization);
153                         exit(0);
154                 }
155                 mirror.key_beg = mirror.key_cur;
156         }
157         fprintf(stderr, "Mirror-write %s succeeded\n", filesystem);
158 }
159
160 void
161 hammer_cmd_mirror_copy(char **av, int ac)
162 {
163 }
164
165 static int
166 read_mrecords(int fd, char *buf, u_int size, hammer_ioc_mrecord_t pickup)
167 {
168         u_int count;
169         size_t n;
170         size_t i;
171
172         count = 0;
173         while (size - count >= HAMMER_MREC_HEADSIZE) {
174                 /*
175                  * Cached the record header in case we run out of buffer
176                  * space.
177                  */
178                 if (pickup->signature == 0) {
179                         for (n = 0; n < HAMMER_MREC_HEADSIZE; n += i) {
180                                 i = read(fd, (char *)pickup + n,
181                                          HAMMER_MREC_HEADSIZE - n);
182                                 if (i <= 0)
183                                         break;
184                         }
185                         if (n == 0)
186                                 break;
187                         if (n != HAMMER_MREC_HEADSIZE) {
188                                 fprintf(stderr, "read_mrecords: short read on pipe\n");
189                                 exit(1);
190                         }
191
192                         if (pickup->signature != HAMMER_IOC_MIRROR_SIGNATURE) {
193                                 fprintf(stderr, "read_mrecords: malformed record on pipe, bad signature\n");
194                                 exit(1);
195                         }
196                         if (pickup->rec_crc != crc32((char *)pickup + HAMMER_MREC_CRCOFF, HAMMER_MREC_HEADSIZE - HAMMER_MREC_CRCOFF)) {
197                                 fprintf(stderr, "read_mrecords: malformed record on pipe, bad crc\n");
198                                 exit(1);
199                         }
200                 }
201                 if (pickup->rec_size < HAMMER_MREC_HEADSIZE ||
202                     pickup->rec_size > HAMMER_MREC_HEADSIZE + HAMMER_XBUFSIZE) {
203                         fprintf(stderr, "read_mrecords: malformed record on pipe, illegal rec_size\n");
204                         exit(1);
205                 }
206                 if (HAMMER_MREC_HEADSIZE + pickup->leaf.data_len > pickup->rec_size) {
207                         fprintf(stderr, "read_mrecords: malformed record on pipe, illegal element data_len\n");
208                         exit(1);
209                 }
210
211                 /*
212                  * Stop if we have insufficient space for the record and data.
213                  */
214                 if (size - count < pickup->rec_size)
215                         break;
216
217                 /*
218                  * Read the remainder and clear the pickup signature.
219                  */
220                 bcopy(pickup, buf + count, HAMMER_MREC_HEADSIZE);
221                 pickup->signature = 0;
222                 for (n = HAMMER_MREC_HEADSIZE; n < pickup->rec_size; n += i) {
223                         i = read(fd, buf + count + n, pickup->rec_size - n);
224                         if (i <= 0)
225                                 break;
226                 }
227                 if (n != pickup->rec_size) {
228                         fprintf(stderr, "read_mrecords: short read on pipe\n");
229                         exit(1);
230                 }
231                 if (pickup->leaf.data_len && pickup->leaf.data_offset) {
232                         if (hammer_crc_test_leaf(buf + count + HAMMER_MREC_HEADSIZE, &pickup->leaf) == 0) {
233                                 fprintf(stderr, "read_mrecords: data_crc did not match data! obj=%016llx key=%016llx\n", pickup->leaf.base.obj_id, pickup->leaf.base.key);
234                                 fprintf(stderr, "continuing, but there are problems\n");
235                         }
236                 }
237
238                 count += pickup->rec_size;
239         }
240         return(count);
241 }
242
243 static void
244 mirror_usage(int code)
245 {
246         fprintf(stderr, 
247                 "hammer mirror-read <filesystem>\n"
248                 "hammer mirror-write <filesystem>\n"
249                 "hammer mirror-copy [[user@]host:]fs [[user@]host:]fs\n"
250         );
251         exit(code);
252 }