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