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