DF-0820 / craft.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | /* * craft.c - DF-0820 superblock geometry patcher. * * Reads a base UFS image (produced by `newfs`), binary-patches selected * struct fs fields at their on-disk offsets (relative to SBOFF=8192), * and writes a crafted image. Used to reproduce the ffs_mountfs * validation gaps cited in sys/vfs/ufs/ffs_vfsops.c:642-709. * * Field offsets (computed from sys/vfs/ufs/fs.h, sizeof(struct fs)=1384): * fs_ncg=44 fs_bsize=48 fs_fsize=52 fs_frag=56 fs_sbsize=104 * fs_cssize=156 fs_cgsize=160 fs_ipg=184 fs_fpg=188 * fs_contigsumsize=1316 fs_magic=1372 * * Usage: craft <base.img> <out.img> <field=value> [<field=value> ...] * field=value sets a 4-byte little-endian int32 field. * field may be a signed decimal (e.g. fs_ncg=-1) or 0x-prefixed hex. * * Build: cc -o craft craft.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #define SBOFF 8192 struct field { const char *name; size_t off; }; static const struct field fields[] = { {"fs_firstfield", 0}, {"fs_sblkno", 8}, {"fs_cgoffset", 24}, {"fs_time", 32}, {"fs_size", 36}, {"fs_dsize", 40}, {"fs_ncg", 44}, {"fs_bsize", 48}, {"fs_fsize", 52}, {"fs_frag", 56}, {"fs_fragshift", 96}, {"fs_sbsize", 104}, {"fs_id", 144}, {"fs_csaddr", 152}, {"fs_cssize", 156}, {"fs_cgsize", 160}, {"fs_ipg", 184}, {"fs_fpg", 188}, {"fs_contigsumsize",1316}, {"fs_maxsymlinklen",1320}, {"fs_postblformat", 1356}, {"fs_magic", 1372}, {NULL, 0} }; static const struct field *findfield(const char *n){ for (int i=0; fields[i].name; i++) if (strcmp(fields[i].name, n)==0) return &fields[i]; return NULL; } int main(int argc, char **argv){ if (argc < 4) { fprintf(stderr, "usage: %s base.img out.img field=val [field=val ...]\n", argv[0]); return 2; } const char *base = argv[1]; const char *out = argv[2]; /* Read whole base image into memory. */ FILE *f = fopen(base, "rb"); if (!f) { perror("open base"); return 2; } fseek(f, 0, SEEK_END); long sz = ftell(f); fseek(f, 0, SEEK_SET); unsigned char *buf = malloc(sz); if (!buf) { perror("malloc"); return 2; } if ((long)fread(buf, 1, sz, f) != sz) { perror("read"); return 2; } fclose(f); /* Sanity: superblock magic at SBOFF+1372 should be 0x00011954. */ uint32_t magic = buf[SBOFF+1372] | (buf[SBOFF+1373]<<8) | (buf[SBOFF+1374]<<16) | ((uint32_t)buf[SBOFF+1375]<<24); if (magic != 0x011954) { fprintf(stderr, "warn: base image fs_magic=0x%x (expected 0x011954)\n", magic); } /* Apply patches. */ for (int a=3; a<argc; a++) { char *arg = argv[a]; char *eq = strchr(arg, '='); if (!eq) { fprintf(stderr, "bad arg '%s' (need field=value)\n", arg); return 2; } *eq = 0; const char *fname = arg; char *vstr = eq+1; const struct field *fl = findfield(fname); if (!fl) { fprintf(stderr, "unknown field '%s'\n", fname); return 2; } /* parse value: signed, with optional 0x */ long long v; char *end; if (vstr[0]=='0' && vstr[1]=='x') v = strtoll(vstr, &end, 16); else v = strtoll(vstr, &end, 10); if (*end != 0) { fprintf(stderr, "bad value '%s' for %s\n", vstr, fname); return 2; } int32_t iv = (int32_t)v; size_t off = SBOFF + fl->off; if ((long)(off+4) > sz) { fprintf(stderr, "offset %zu out of range (img %ld)\n", off, sz); return 2; } buf[off+0] = (unsigned char)(iv & 0xff); buf[off+1] = (unsigned char)((iv >> 8) & 0xff); buf[off+2] = (unsigned char)((iv >> 16) & 0xff); buf[off+3] = (unsigned char)((iv >> 24) & 0xff); printf("patched %s @ file off %zu (struct off %zu) = %d (0x%08x)\n", fname, off, fl->off, iv, (unsigned)iv); } FILE *o = fopen(out, "wb"); if (!o) { perror("open out"); return 2; } if ((long)fwrite(buf, 1, sz, o) != sz) { perror("write"); return 2; } fclose(o); free(buf); printf("wrote %s (%ld bytes)\n", out, sz); return 0; } |