Major continuing work on jscan, the userland backend for the journaling
[dragonfly.git] / sbin / jscan / dump_debug.c
1 /*
2  * Copyright (c) 2003,2004 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_debug.c,v 1.3 2005/07/05 00:26:03 dillon Exp $
35  */
36
37 #include "jscan.h"
38
39 static void dump_debug_stream(struct jstream *js);
40 static int dump_debug_subrecord(struct jstream *js, off_t *off, 
41                                 off_t recsize, int level);
42
43 void
44 dump_debug(struct jfile *jf)
45 {
46     struct jstream *js;
47
48     while ((js = jscan_stream(jf)) != NULL) {
49         dump_debug_stream(js);
50         jscan_dispose(js);
51     }
52 }
53
54 static void
55 dump_debug_stream(struct jstream *js)
56 {
57         struct journal_rawrecbeg head;
58         int16_t sid;
59
60         jsread(js, 0, &head, sizeof(head));
61
62         sid = head.streamid & JREC_STREAMID_MASK;
63         printf("STREAM %04x {\n", (int)(u_int16_t)head.streamid);
64         if (sid >= JREC_STREAMID_JMIN && sid < JREC_STREAMID_JMAX) {
65             off_t off = sizeof(head);
66
67             dump_debug_subrecord(js, &off,
68                         js->js_normalized_total - sizeof(head),
69                         1);
70         } else {
71             switch(head.streamid & JREC_STREAMID_MASK) {
72             case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
73                 printf("    SYNCPT\n");
74                 break;
75             case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
76                 printf("    PAD\n");
77                 break;
78             case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
79                 printf("    DISCONT\n");
80                 break;
81             case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
82                 printf("    ANNOTATION\n");
83                 break;
84             default:
85                 printf("    UNKNOWN\n");
86                 break;
87             }
88         }
89         printf("}\n");
90 }
91
92 static int
93 dump_debug_subrecord(struct jstream *js, off_t *off, off_t recsize, int level)
94 {
95     struct journal_subrecord sub;
96     int payload;
97     int subsize;
98     int error;
99     off_t base = *off;
100
101     error = 0;
102     while (recsize > 0) {
103         if ((error = jsread(js, base, &sub, sizeof(sub))) != 0) {
104             break;
105         }
106         printf("%*.*s", level * 4, level * 4, "");
107         printf("@%lld ", base);
108         printf("RECORD %s [%04x/%d]", type_to_name(sub.rectype), 
109                                 (int)(u_int16_t)sub.rectype, sub.recsize);
110         if (sub.recsize == -1) {
111             if ((sub.rectype & JMASK_NESTED) == 0) {
112                 printf("Record size of -1 only works for nested records\n");
113                 error = -1;
114                 break;
115             }
116             payload = 0x7FFFFFFF;
117             subsize = 0x7FFFFFFF;
118         } else {
119             payload = sub.recsize - sizeof(sub);
120             subsize = (sub.recsize + 7) & ~7;
121         }
122         if (sub.rectype & JMASK_NESTED) {
123             printf(" {\n");
124             if (payload) {
125                 *off = base + sizeof(sub);
126                 error = dump_debug_subrecord(js, off, payload, level + 1);
127             }
128             printf("%*.*s}\n", level * 4, level * 4, "");
129         } else if (sub.rectype & JMASK_SUBRECORD) {
130             printf(" DATA (%d)", payload);
131             error = dump_debug_payload(sub.rectype, js, base + sizeof(sub), payload, level);
132             *off = base + sizeof(sub) + payload;
133             printf("\n");
134         } else {
135             printf("[%d bytes of unknown content]\n", sub.recsize);
136         }
137         if (error)
138             break;
139         if (sub.recsize == -1) {
140             recsize -= ((*off + 7) & ~7) - base;
141             base = (*off + 7) & ~7;
142         } else {
143             if (subsize == 0)
144                 subsize = sizeof(sub);
145             recsize -= subsize;
146             base += subsize;
147         }
148         if (sub.rectype & JMASK_LAST)
149                 break;
150     }
151     *off = base;
152     return(error);
153 }
154
155 int
156 dump_debug_payload(int16_t rectype, struct jstream *js, off_t off, 
157              int recsize, int level)
158 {
159     enum { DT_NONE, DT_STRING, DT_DEC, DT_HEX, DT_OCT,
160            DT_DATA, DT_TIMESTAMP } dt = DT_DATA;
161     const char *buf;
162     int error;
163     int i;
164     int j;
165
166     error = jsreadp(js, off, (const void **)&buf, recsize);
167     if (error)
168         return (error);
169
170     switch(rectype & ~JMASK_LAST) {
171     case JLEAF_PAD:
172     case JLEAF_ABORT:
173         break;
174     case JLEAF_FILEDATA:
175         break;
176     case JLEAF_PATH1:
177     case JLEAF_PATH2:
178     case JLEAF_PATH3:
179     case JLEAF_PATH4:
180         dt = DT_STRING;
181         break;
182     case JLEAF_UID:
183     case JLEAF_GID:
184     case JLEAF_VTYPE:
185         dt = DT_DEC;
186         break;
187     case JLEAF_MODES:
188         dt = DT_OCT;
189         break;
190     case JLEAF_FFLAGS:
191         dt = DT_HEX;
192         break;
193     case JLEAF_PID:
194     case JLEAF_PPID:
195         dt = DT_DEC;
196         break;
197     case JLEAF_COMM:
198         dt = DT_STRING;
199         break;
200     case JLEAF_ATTRNAME:
201         dt = DT_STRING;
202         break;
203     case JLEAF_PATH_REF:
204         dt = DT_STRING;
205         break;
206     case JLEAF_RESERVED_0F:
207         break;
208     case JLEAF_SYMLINKDATA:
209         dt = DT_STRING;
210         break;
211     case JLEAF_SEEKPOS:
212         dt = DT_HEX;
213         break;
214     case JLEAF_INUM:
215         dt = DT_HEX;
216         break;
217     case JLEAF_NLINK:
218         dt = DT_DEC;
219         break;
220     case JLEAF_FSID:
221         dt = DT_HEX;
222         break;
223     case JLEAF_SIZE:
224         dt = DT_HEX;
225         break;
226     case JLEAF_ATIME:
227     case JLEAF_MTIME:
228     case JLEAF_CTIME:
229         dt = DT_TIMESTAMP;
230         break;
231     case JLEAF_GEN:
232         dt = DT_HEX;
233         break;
234     case JLEAF_FLAGS:
235         dt = DT_HEX;
236         break;
237     case JLEAF_UDEV:
238         dt = DT_HEX;
239         break;
240     case JLEAF_FILEREV:
241         dt = DT_HEX;
242         break;
243     default:
244         break;
245     }
246     switch(dt) {
247     case DT_NONE:
248         break;
249     case DT_STRING:
250         printf(" \"");
251         for (i = 0; i < recsize; ++i)
252             stringout(stdout, buf[i], 1);
253         printf("\"");
254         break;
255     case DT_DEC:
256         switch(recsize) {
257         case 1:
258             printf(" %d", (int)*(const u_int8_t *)buf);
259             break;
260         case 2:
261             printf(" %d", (int)*(const u_int16_t *)buf);
262             break;
263         case 4:
264             printf(" %d", (int)*(const u_int32_t *)buf);
265             break;
266         case 8:
267             printf(" %lld", (int64_t)*(const u_int64_t *)buf);
268             break;
269         default:
270             printf(" ?");
271             break;
272         }
273         break;
274     case DT_HEX:
275         switch(recsize) {
276         case 1:
277             printf(" 0x%02x", (int)*(const u_int8_t *)buf);
278             break;
279         case 2:
280             printf(" 0x%04x", (int)*(const u_int16_t *)buf);
281             break;
282         case 4:
283             printf(" 0x%08x", (int)*(const u_int32_t *)buf);
284             break;
285         case 8:
286             printf(" 0x%016llx", (int64_t)*(const u_int64_t *)buf);
287             break;
288         default:
289             printf(" ?");
290             break;
291         }
292         break;
293     case DT_OCT:
294         switch(recsize) {
295         case 1:
296             printf(" %03o", (int)*(const u_int8_t *)buf);
297             break;
298         case 2:
299             printf(" %06o", (int)*(const u_int16_t *)buf);
300             break;
301         case 4:
302             printf(" %011o", (int)*(const u_int32_t *)buf);
303             break;
304         case 8:
305             printf(" %022llo", (int64_t)*(const u_int64_t *)buf);
306             break;
307         default:
308             printf(" ?");
309             break;
310         }
311         break;
312     case DT_TIMESTAMP:
313         {
314             struct tm *tp;
315             time_t t = ((const struct timespec *)buf)->tv_sec;
316             char outbuf[64];
317
318             tp = localtime(&t);
319             strftime(outbuf, sizeof(outbuf), " <%d-%b-%Y %H:%M:%S>", tp);
320             printf("%s", outbuf);
321         }
322         break;
323     case DT_DATA:
324     default:
325         if (recsize < 16) {
326             for (i = 0; i < recsize; ++i)
327                 printf(" %02x", (int)(unsigned char)buf[i]);
328             printf(" \"");
329             for (i = 0; i < recsize; ++i)
330                 stringout(stdout, buf[i], 0);
331             printf("\"");
332         } else {
333             printf(" {\n");
334             for (i = 0; i < recsize; i += 16) {
335                 printf("%*.*s", level * 4 + 4, level * 4 + 4, "");
336                 for (j = i; j < i + 16 && j < recsize; ++j)
337                     printf(" %02x", (int)(unsigned char)buf[j]);
338                 for (; j < i + 16; ++j)
339                     printf("   ");
340                 printf(" \"");
341                 for (j = i; j < i + 16 && j < recsize; ++j)
342                     stringout(stdout, buf[j], 0);
343                 printf("\"\n");
344             }
345             printf("%*.*s}", level * 4, level * 4, "");
346         }
347         break;
348     }
349     return (0);
350 }
351