xref: /dragonfly/sbin/jscan/dump_mirror.c (revision 6bd457ed)
1 /*
2  * Copyright (c) 2005 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/jscan/dump_mirror.c,v 1.4 2005/07/05 06:20:07 dillon Exp $
35  */
36 
37 #include "jscan.h"
38 
39 static void dump_mirror_stream(struct jstream *js);
40 static int dump_mirror_toprecord(struct jstream *js, off_t *off,
41 				 off_t recsize, int level);
42 static int dump_mirror_subrecord(struct jstream *js, off_t *off,
43 				 off_t recsize, int level, struct jattr *jattr);
44 static int dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
45 				 int recsize, int level, struct jattr *jattr);
46 static int dump_mirror_rebuild(u_int16_t rectype, struct jstream *js, struct jattr *jattr);
47 
48 void
49 dump_mirror(struct jfile *jf)
50 {
51     struct jstream *js;
52 
53     while ((js = jscan_stream(jf)) != NULL) {
54 	dump_mirror_stream(js);
55 	jscan_dispose(js);
56     }
57 }
58 
59 static void
60 dump_mirror_stream(struct jstream *js)
61 {
62 	struct journal_rawrecbeg head;
63 	int16_t sid;
64 	mode_t save_umask;
65 
66 	save_umask = umask(0);
67 	jsread(js, 0, &head, sizeof(head));
68 
69 	sid = head.streamid & JREC_STREAMID_MASK;
70 	if (debug_opt) {
71 	    printf("STREAM %04x DATA (%lld) {\n",
72 		(int)(u_int16_t)head.streamid, js->js_normalized_total);
73 	}
74 	if (sid >= JREC_STREAMID_JMIN && sid < JREC_STREAMID_JMAX) {
75 	    off_t off = sizeof(head);
76 	    dump_mirror_toprecord(js, &off, js->js_normalized_total -
77 				  sizeof(struct journal_rawrecbeg),
78 				  1);
79 	} else {
80 	    switch(head.streamid & JREC_STREAMID_MASK) {
81 	    case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
82 		if (debug_opt)
83 		    printf("    SYNCPT\n");
84 		break;
85 	    case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
86 		if (debug_opt)
87 		    printf("    PAD\n");
88 		break;
89 	    case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
90 		if (debug_opt)
91 		    printf("    DISCONT\n");
92 		break;
93 	    case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
94 		if (debug_opt)
95 		    printf("    ANNOTATION\n");
96 		break;
97 	    default:
98 		if (debug_opt)
99 		    printf("    UNKNOWN\n");
100 		break;
101 	    }
102 	}
103 	umask(save_umask);
104 	if (debug_opt) {
105 	    printf("}\n");
106 	    fflush(stdout);
107 	}
108 }
109 
110 static int
111 dump_mirror_toprecord(struct jstream *js, off_t *off, off_t recsize, int level)
112 {
113     struct journal_subrecord sub;
114     struct jattr jattr;
115     int payload;
116     int subsize;
117     int error;
118     off_t base = *off;
119 
120     error = 0;
121     bzero(&jattr, sizeof(jattr));
122     jattr_reset(&jattr);
123 
124     while (recsize > 0) {
125 	if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
126 	    break;
127 	if (debug_opt) {
128 	    printf("%*.*s", level * 4, level * 4, "");
129 	    printf("@%lld ", base);
130 	    printf("RECORD %s [%04x/%d]", type_to_name(sub.rectype),
131 		   (int)(u_int16_t)sub.rectype, sub.recsize);
132 	}
133 	if (sub.recsize == -1) {
134 	    if ((sub.rectype & JMASK_NESTED) == 0) {
135 		printf("Record size of -1 only works for nested records\n");
136 		error = -1;
137 		break;
138 	    }
139 	    payload = 0x7FFFFFFF;
140 	    subsize = 0x7FFFFFFF;
141 	} else {
142 	    payload = sub.recsize - sizeof(sub);
143 	    subsize = (sub.recsize + 7) & ~7;
144 	}
145 	if (sub.rectype & JMASK_NESTED) {
146 	    if (debug_opt)
147 		printf(" {\n");
148 	    *off = base + sizeof(sub);
149 	    error = dump_mirror_subrecord(js, off,
150 					  payload, level + 1, &jattr);
151 	    if (debug_opt)
152 		printf("%*.*s}\n", level * 4, level * 4, "");
153 	} else if (sub.rectype & JMASK_SUBRECORD) {
154 	    if (debug_opt) {
155 		printf(" DATA (%d)", payload);
156 		error = dump_debug_payload(sub.rectype, js, base + sizeof(sub), payload, level);
157 	    }
158 	    *off = base + sizeof(sub) + payload;
159 	    if (debug_opt)
160 		printf("\n");
161 	} else if ((sub.rectype & JTYPE_MASK) == JLEAF_PAD) {
162 	    if (debug_opt) {
163 		if (payload)
164 		    printf(" DATA (%d)", payload);
165 		printf("\n");
166 	    }
167 	} else {
168 	    if (debug_opt)
169 		printf("[%d bytes of unknown content]\n", payload);
170 	}
171 	dump_mirror_rebuild(sub.rectype, js, &jattr);
172 	jattr_reset(&jattr);
173 	if (error)
174 	    break;
175 	if (sub.recsize == -1) {
176 	    if ((sub.rectype & JMASK_NESTED) == 0) {
177 		printf("Record size of -1 only works for nested records\n");
178 		error = -1;
179 		break;
180 	    }
181 	    recsize -= ((*off + 7) & ~7) - base;
182 	    base = (*off + 7) & ~7;
183 	} else {
184 	    if (subsize == 0)
185 		subsize = sizeof(sub);
186 	    recsize -= subsize;
187 	    base += subsize;
188 	}
189 	if (sub.rectype & JMASK_LAST)
190 	    break;
191     }
192     *off = base;
193     return(error);
194 }
195 
196 static int
197 dump_mirror_subrecord(struct jstream *js, off_t *off, off_t recsize, int level,
198 		      struct jattr *jattr)
199 {
200     struct journal_subrecord sub;
201     int payload;
202     int subsize;
203     int error;
204     u_int16_t rectype;
205     off_t base = *off;
206 
207     error = 0;
208     while (recsize > 0) {
209 	if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
210 	    break;
211 	rectype = sub.rectype & JTYPE_MASK;
212 	if (debug_opt) {
213 	    printf("%*.*s", level * 4, level * 4, "");
214 	    printf("@%lld ", base);
215 	    printf("SRECORD %s [%04x/%d]", type_to_name(sub.rectype),
216 		   (int)(u_int16_t)sub.rectype, sub.recsize);
217 	}
218 	if (sub.recsize == -1) {
219 	    payload = 0x7FFFFFFF;
220 	    subsize = 0x7FFFFFFF;
221 	} else {
222 	    payload = sub.recsize - sizeof(sub);
223 	    subsize = (sub.recsize + 7) & ~7;
224 	}
225 	if (sub.rectype & JMASK_NESTED) {
226 	    if (debug_opt)
227 		printf(" {\n");
228 
229 	    /*
230 	     * Only recurse through vattr records.  XXX currently assuming
231 	     * only on VATTR subrecord.
232 	     */
233 	    *off = base + sizeof(sub);
234 	    if (payload && rectype == JTYPE_VATTR) {
235 		error = dump_mirror_subrecord(js, off,
236 					      payload, level + 1, jattr);
237 	    } else {
238 		error = dump_mirror_subrecord(js, off,
239 					      payload, level + 1, NULL);
240 	    }
241 	    if (debug_opt)
242 		printf("%*.*s}\n", level * 4, level * 4, "");
243 	} else if (sub.rectype & JMASK_SUBRECORD) {
244 	    if (debug_opt) {
245 		printf(" DATA (%d)", payload);
246 		dump_debug_payload(sub.rectype, js, base + sizeof(sub),
247 				   payload, level);
248 	    }
249 	    error = dump_mirror_payload(sub.rectype, js, base + sizeof(sub),
250 				       payload, level, jattr);
251 	    *off = base + sizeof(sub) + payload;
252 	    if (debug_opt)
253 		printf("\n");
254 	} else if ((sub.rectype & JTYPE_MASK) == JLEAF_PAD) {
255 	    if (debug_opt) {
256 		if (payload)
257 		    printf(" DATA (%d)", payload);
258 		printf("\n");
259 	    }
260 	} else {
261 	    if (debug_opt)
262 		printf("[%d bytes of unknown content]\n", sub.recsize);
263 	}
264 	if (error)
265 	    break;
266 	if (sub.recsize == -1) {
267 	    recsize -= ((*off + 7) & ~7) - base;
268 	    base = (*off + 7) & ~7;
269 	} else {
270 	    if (subsize == 0)
271 		subsize = sizeof(sub);
272 	    recsize -= subsize;
273 	    base += subsize;
274 	}
275 	if (sub.rectype & JMASK_LAST)
276 	    break;
277     }
278     *off = base;
279     return(error);
280 }
281 
282 static int
283 dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
284 	     int recsize, int level __unused, struct jattr *jattr)
285 {
286     const char *buf;
287     struct jattr_data *data;
288     int error;
289 
290     if (jattr == NULL)
291 	return (0);
292 
293     if ((rectype & ~JMASK_LAST) != JLEAF_FILEDATA) {
294 	error = jsreadp(js, off, (const void **)&buf, recsize);
295 	if (error)
296 	    return (error);
297     } else {
298 	buf = NULL;
299 	error = 0;
300     }
301 
302     switch(rectype & ~JMASK_LAST) {
303     case JLEAF_PAD:
304     case JLEAF_ABORT:
305 	break;
306     case JLEAF_SYMLINKDATA:
307 	jattr->symlinkdata = dupdatastr(buf, recsize);
308 	jattr->symlinklen = recsize;
309 	break;
310     case JLEAF_FILEDATA:
311 	if ((data = jattr->last_data) == NULL) {
312 		jattr->data.off = off;
313 		jattr->data.bytes = recsize;
314 		jattr->last_data = &jattr->data;
315 	} else {
316 		data->next = malloc(sizeof(jattr->data));
317 		data = data->next;
318 		data->off = off;
319 		data->bytes = recsize;
320 		data->next = NULL;
321 		jattr->last_data = data;
322 	}
323 	break;
324     case JLEAF_PATH1:
325 	jattr->path1 = dupdatapath(buf, recsize);
326 	break;
327     case JLEAF_PATH2:
328 	jattr->path2 = dupdatapath(buf, recsize);
329 	break;
330     case JLEAF_PATH3:
331 	jattr->path3 = dupdatapath(buf, recsize);
332 	break;
333     case JLEAF_PATH4:
334 	jattr->path4 = dupdatapath(buf, recsize);
335 	break;
336     case JLEAF_UID:
337 	jattr->uid = buf_to_int64(buf, recsize);
338 	break;
339     case JLEAF_GID:
340 	jattr->gid = buf_to_int64(buf, recsize);
341 	break;
342     case JLEAF_VTYPE:
343 	jattr->vtype = buf_to_int64(buf, recsize);
344 	break;
345     case JLEAF_MODES:
346 	jattr->modes = buf_to_int64(buf, recsize);
347 	break;
348     case JLEAF_FFLAGS:
349 	jattr->fflags = buf_to_int64(buf, recsize);
350 	break;
351     case JLEAF_PID:
352 	jattr->pid = buf_to_int64(buf, recsize);
353 	break;
354     case JLEAF_PPID:
355 	jattr->ppid = buf_to_int64(buf, recsize);
356 	break;
357     case JLEAF_COMM:
358 	jattr->comm = dupdatastr(buf, recsize);
359 	break;
360     case JLEAF_ATTRNAME:
361 	jattr->attrname = dupdatastr(buf, recsize);
362 	break;
363     case JLEAF_PATH_REF:
364 	jattr->pathref = dupdatapath(buf, recsize);
365 	break;
366     case JLEAF_RESERVED_0F:
367 	break;
368     case JLEAF_SEEKPOS:
369 	jattr->seekpos = buf_to_int64(buf, recsize);
370 	break;
371     case JLEAF_INUM:
372 	jattr->inum = buf_to_int64(buf, recsize);
373 	break;
374     case JLEAF_NLINK:
375 	jattr->nlink = buf_to_int64(buf, recsize);
376 	break;
377     case JLEAF_FSID:
378 	jattr->fsid = buf_to_int64(buf, recsize);
379 	break;
380     case JLEAF_SIZE:
381 	jattr->size = buf_to_int64(buf, recsize);
382 	break;
383     case JLEAF_ATIME:
384 	jattr->atime = *(const struct timeval *)buf;
385 	break;
386     case JLEAF_MTIME:
387 	jattr->mtime = *(const struct timeval *)buf;
388 	break;
389     case JLEAF_CTIME:
390 	jattr->ctime = *(const struct timeval *)buf;
391 	break;
392     case JLEAF_GEN:
393 	jattr->gen = buf_to_int64(buf, recsize);
394 	break;
395     case JLEAF_FLAGS:
396 	jattr->flags = buf_to_int64(buf, recsize);
397 	break;
398     case JLEAF_UDEV:
399 	jattr->udev = buf_to_int64(buf, recsize);
400 	break;
401     case JLEAF_FILEREV:
402 	jattr->filerev = buf_to_int64(buf, recsize);
403 	break;
404     default:
405 	break;
406     }
407     return (0);
408 }
409 
410 static int
411 dump_mirror_rebuild(u_int16_t rectype, struct jstream *js, struct jattr *jattr)
412 {
413     struct jattr_data *data;
414     int error = 0;
415     int fd;
416 
417 again:
418     switch(rectype) {
419     case JTYPE_SETATTR:
420 	if (jattr->pathref) {
421 	    if (jattr->uid != (uid_t)-1)
422 		chown(jattr->pathref, jattr->uid, -1);
423 	    if (jattr->gid != (gid_t)-1)
424 		chown(jattr->pathref, -1, jattr->gid);
425 	    if (jattr->modes != (mode_t)-1)
426 		chmod(jattr->pathref, jattr->modes);
427 	    if (jattr->fflags != -1)
428 		chflags(jattr->pathref, jattr->fflags);
429 	    if (jattr->size != -1)
430 		truncate(jattr->pathref, jattr->size);
431 	}
432 	break;
433     case JTYPE_WRITE:
434     case JTYPE_PUTPAGES:
435 	if (jattr->pathref && jattr->seekpos != -1) {
436 	    if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
437 		lseek(fd, jattr->seekpos, 0);
438 		for (data = &jattr->data; data; data = data->next) {
439 		    if (data->bytes)
440 			jsreadcallback(js, write, fd, data->off, data->bytes);
441 		}
442 		close(fd);
443 	    }
444 	}
445 	break;
446     case JTYPE_SETACL:
447 	break;
448     case JTYPE_SETEXTATTR:
449 	break;
450     case JTYPE_CREATE:
451 	/*
452 	 * note: both path1 and pathref will exist.
453 	 */
454 	if (jattr->path1 && jattr->modes != (mode_t)-1) {
455 	    if ((fd = open(jattr->path1, O_CREAT, jattr->modes)) >= 0) {
456 		close(fd);
457 		rectype = JTYPE_SETATTR;
458 		goto again;
459 	    }
460 	}
461 	break;
462     case JTYPE_MKNOD:
463 	break;
464     case JTYPE_LINK:
465 	if (jattr->pathref && jattr->path1) {
466 	    link(jattr->pathref, jattr->path1);
467 	}
468 	break;
469     case JTYPE_SYMLINK:
470 	if (jattr->symlinkdata && jattr->path1) {
471 	    symlink(jattr->symlinkdata, jattr->path1);
472 	}
473 	break;
474     case JTYPE_WHITEOUT:
475 	break;
476     case JTYPE_REMOVE:
477 	if (jattr->path1) {
478 	    remove(jattr->path1);
479 	}
480 	break;
481     case JTYPE_MKDIR:
482 	if (jattr->path1 && jattr->modes != (mode_t)-1) {
483 	    mkdir(jattr->path1, jattr->modes);
484 	}
485 	break;
486     case JTYPE_RMDIR:
487 	if (jattr->path1) {
488 	    rmdir(jattr->path1);
489 	}
490 	break;
491     case JTYPE_RENAME:
492 	if (jattr->path1 && jattr->path2) {
493 	    rename(jattr->path1, jattr->path2);
494 	}
495 	break;
496     }
497     return(error);
498 }
499 
500