1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <disk.h>
5 #include <libsec.h>
6 #include "iso9660.h"
7
8 ulong now;
9 int chatty;
10 int doabort;
11 int docolon;
12 int mk9660;
13 vlong dataoffset;
14 int blocksize;
15 Conform *map;
16
17 static void addprotofile(char *new, char *old, Dir *d, void *a);
18 void usage(void);
19
20 char *argv0;
21
22 void
usage(void)23 usage(void)
24 {
25 if(mk9660)
26 fprint(2, "usage: disk/mk9660 [-D:] [-9cjr] "
27 "[-[bB] bootfile] [-o offset blocksize] "
28 "[-p proto] [-s src] cdimage\n");
29 else
30 fprint(2, "usage: disk/dump9660 [-D:] [-9cjr] "
31 "[-m maxsize] [-n now] "
32 "[-p proto] [-s src] cdimage\n");
33 exits("usage");
34 }
35
36 void
main(int argc,char ** argv)37 main(int argc, char **argv)
38 {
39 int fix;
40 ulong block, newnull, cblock;
41 vlong maxsize;
42 uvlong length, clength;
43 char buf[256], *dumpname, *proto, *s, *src, *status;
44 Cdimg *cd;
45 Cdinfo info;
46 XDir dir;
47 Direc *iconform, idumproot, iroot, *jconform, jdumproot, jroot, *r;
48 Dump *dump;
49
50 fix = 0;
51 status = nil;
52 memset(&info, 0, sizeof info);
53 proto = "/sys/lib/sysconfig/proto/allproto";
54 src = "./";
55
56 info.volumename = atom("9CD");
57 info.volumeset = atom("9VolumeSet");
58 info.publisher = atom("9Publisher");
59 info.preparer = atom("dump9660");
60 info.application = atom("dump9660");
61 info.flags = CDdump;
62 maxsize = 0;
63 mk9660 = 0;
64 fmtinstall('H', encodefmt);
65
66 ARGBEGIN{
67 case 'D':
68 chatty++;
69 break;
70 case 'M':
71 mk9660 = 1;
72 argv0 = "disk/mk9660";
73 info.flags &= ~CDdump;
74 break;
75 case '9':
76 info.flags |= CDplan9;
77 break;
78 case ':':
79 docolon = 1;
80 break;
81 case 'a':
82 doabort = 1;
83 break;
84 case 'B':
85 info.flags |= CDbootnoemu;
86 /* fall through */
87 case 'b':
88 if(!mk9660)
89 usage();
90 info.flags |= CDbootable;
91 info.bootimage = EARGF(usage());
92 break;
93 case 'c':
94 info.flags |= CDconform;
95 break;
96 case 'f':
97 fix = 1;
98 break;
99 case 'j':
100 info.flags |= CDjoliet;
101 break;
102 case 'n':
103 now = atoi(EARGF(usage()));
104 break;
105 case 'm':
106 maxsize = strtoull(EARGF(usage()), 0, 0);
107 break;
108 case 'o':
109 dataoffset = atoll(EARGF(usage()));
110 blocksize = atoi(EARGF(usage()));
111 if(blocksize%Blocksize)
112 sysfatal("bad block size %d -- must be multiple of 2048", blocksize);
113 blocksize /= Blocksize;
114 break;
115 case 'p':
116 proto = EARGF(usage());
117 break;
118 case 'r':
119 info.flags |= CDrockridge;
120 break;
121 case 's':
122 src = EARGF(usage());
123 break;
124 case 'v':
125 info.volumename = atom(EARGF(usage()));
126 break;
127 case 'x':
128 info.flags |= CDpbs;
129 info.loader = EARGF(usage());
130 break;
131 default:
132 usage();
133 }ARGEND
134
135 if(info.flags & CDpbs && !(info.flags & CDbootnoemu))
136 usage();
137
138 if(mk9660 && (fix || now || maxsize))
139 usage();
140
141 if(argc != 1)
142 usage();
143
144 if(now == 0)
145 now = (ulong)time(0);
146 if(mk9660){
147 if((cd = createcd(argv[0], info)) == nil)
148 sysfatal("cannot create '%s': %r", argv[0]);
149 }else{
150 if((cd = opencd(argv[0], info)) == nil)
151 sysfatal("cannot open '%s': %r", argv[0]);
152 if(!(cd->flags & CDdump))
153 sysfatal("not a dump cd");
154 }
155
156 /* create ISO9660/Plan 9 tree in memory */
157 memset(&dir, 0, sizeof dir);
158 dir.name = atom("");
159 dir.uid = atom("sys");
160 dir.gid = atom("sys");
161 dir.uidno = 0;
162 dir.gidno = 0;
163 dir.mode = DMDIR | 0755;
164 dir.mtime = now;
165 dir.atime = now;
166 dir.ctime = now;
167
168 mkdirec(&iroot, &dir);
169 iroot.srcfile = src;
170
171 /*
172 * Read new files into memory
173 */
174 if(rdproto(proto, src, addprotofile, nil, &iroot) < 0)
175 sysfatal("rdproto: %r");
176
177 if(mk9660){
178 dump = emalloc(sizeof *dump);
179 dumpname = nil;
180 }else{
181 /*
182 * Read current dump tree and _conform.map.
183 */
184 idumproot = readdumpdirs(cd, &dir, isostring);
185 readdumpconform(cd);
186 if(cd->flags & CDjoliet)
187 jdumproot = readdumpdirs(cd, &dir, jolietstring);
188
189 if(fix){
190 dumpname = nil;
191 cd->nextblock = cd->nulldump+1;
192 cd->nulldump = 0;
193 Cwseek(cd, (vlong)cd->nextblock * Blocksize);
194 goto Dofix;
195 }
196
197 dumpname = adddumpdir(&idumproot, now, &dir);
198 /* note that we assume all names are conforming and thus sorted */
199 if(cd->flags & CDjoliet) {
200 s = adddumpdir(&jdumproot, now, &dir);
201 if(s != dumpname)
202 sysfatal("dumpnames don't match %s %s", dumpname, s);
203 }
204 dump = dumpcd(cd, &idumproot);
205 cd->nextblock = cd->nulldump+1;
206 }
207
208 /*
209 * Write new files, starting where the dump tree was.
210 * Must be done before creation of the Joliet tree so that
211 * blocks and lengths are correct.
212 */
213 if(dataoffset > (vlong)cd->nextblock * Blocksize)
214 cd->nextblock = (dataoffset+Blocksize-1)/Blocksize;
215 Cwseek(cd, (vlong)cd->nextblock * Blocksize);
216 writefiles(dump, cd, &iroot);
217
218 if(cd->bootimage){
219 findbootimage(cd, &iroot);
220 if(cd->loader)
221 findloader(cd, &iroot);
222 Cupdatebootcat(cd);
223 }
224
225 /* create Joliet tree */
226 if(cd->flags & CDjoliet)
227 copydirec(&jroot, &iroot);
228
229 if(info.flags & CDconform) {
230 checknames(&iroot, isbadiso9660);
231 convertnames(&iroot, struprcpy);
232 } else
233 convertnames(&iroot, (void *) strcpy);
234
235 // isoabstract = findconform(&iroot, abstract);
236 // isobiblio = findconform(&iroot, biblio);
237 // isonotice = findconform(&iroot, notice);
238
239 dsort(&iroot, isocmp);
240
241 if(cd->flags & CDjoliet) {
242 // jabstract = findconform(&jroot, abstract);
243 // jbiblio = findconform(&jroot, biblio);
244 // jnotice = findconform(&jroot, notice);
245
246 checknames(&jroot, isbadjoliet);
247 convertnames(&jroot, (void *) strcpy);
248 dsort(&jroot, jolietcmp);
249 }
250
251 /*
252 * Write directories.
253 */
254 writedirs(cd, &iroot, Cputisodir);
255 if(cd->flags & CDjoliet)
256 writedirs(cd, &jroot, Cputjolietdir);
257
258 if(mk9660){
259 cblock = 0;
260 clength = 0;
261 newnull = 0;
262 }else{
263 /*
264 * Write incremental _conform.map block.
265 */
266 wrconform(cd, cd->nconform, &cblock, &clength);
267
268 /* jump here if we're just fixing up the cd */
269 Dofix:
270 /*
271 * Write null dump header block; everything after this will be
272 * overwritten at the next dump. Because of this, it needs to be
273 * reconstructable. We reconstruct the _conform.map and dump trees
274 * from the header blocks in dump.c, and we reconstruct the path
275 * tables by walking the cd.
276 */
277 newnull = Cputdumpblock(cd);
278 }
279 if(info.flags & CDpbs)
280 Cfillpbs(cd);
281
282 /*
283 * Write _conform.map.
284 */
285 dir.mode = 0444;
286 if(cd->flags & (CDconform|CDjoliet)) {
287 if(!mk9660 && cd->nconform == 0){
288 block = cblock;
289 length = clength;
290 }else
291 wrconform(cd, 0, &block, &length);
292
293 if(mk9660)
294 {
295 idumproot = iroot;
296 jdumproot = jroot;
297 }
298 if(length) {
299 /* The ISO9660 name will get turned into uppercase when written. */
300 if((iconform = walkdirec(&idumproot, "_conform.map")) == nil)
301 iconform = adddirec(&idumproot, "_conform.map", &dir);
302 jconform = nil;
303 if(cd->flags & CDjoliet) {
304 if((jconform = walkdirec(&jdumproot, "_conform.map")) == nil)
305 jconform = adddirec(&jdumproot, "_conform.map", &dir);
306 }
307 iconform->block = block;
308 iconform->length = length;
309 if(cd->flags & CDjoliet) {
310 jconform->block = block;
311 jconform->length = length;
312 }
313 }
314 if(mk9660) {
315 iroot = idumproot;
316 jroot = jdumproot;
317 }
318 }
319
320 if(mk9660){
321 /*
322 * Patch in root directories.
323 */
324 setroot(cd, cd->iso9660pvd, iroot.block, iroot.length);
325 setvolsize(cd, cd->iso9660pvd, cd->nextblock);
326 if(cd->flags & CDjoliet){
327 setroot(cd, cd->jolietsvd, jroot.block, jroot.length);
328 setvolsize(cd, cd->jolietsvd, cd->nextblock);
329 }
330 }else{
331 /*
332 * Write dump tree at end. We assume the name characters
333 * are all conforming, so everything is already sorted properly.
334 */
335 convertnames(&idumproot, (info.flags & CDconform) ? (void *) struprcpy : (void *) strcpy);
336 if(cd->nulldump) {
337 r = walkdirec(&idumproot, dumpname);
338 assert(r != nil);
339 copybutname(r, &iroot);
340 }
341 if(cd->flags & CDjoliet) {
342 convertnames(&jdumproot, (void *) strcpy);
343 if(cd->nulldump) {
344 r = walkdirec(&jdumproot, dumpname);
345 assert(r != nil);
346 copybutname(r, &jroot);
347 }
348 }
349
350 writedumpdirs(cd, &idumproot, Cputisodir);
351 if(cd->flags & CDjoliet)
352 writedumpdirs(cd, &jdumproot, Cputjolietdir);
353
354 /*
355 * Patch in new root directory entry.
356 */
357 setroot(cd, cd->iso9660pvd, idumproot.block, idumproot.length);
358 setvolsize(cd, cd->iso9660pvd, cd->nextblock);
359 if(cd->flags & CDjoliet){
360 setroot(cd, cd->jolietsvd, jdumproot.block, jdumproot.length);
361 setvolsize(cd, cd->jolietsvd, cd->nextblock);
362 }
363 }
364 writepathtables(cd);
365
366 if(!mk9660){
367 /*
368 * If we've gotten too big, truncate back to what we started with,
369 * fix up the cd, and exit with a non-zero status.
370 */
371 Cwflush(cd);
372 if(cd->nulldump && maxsize && Cwoffset(cd) > maxsize){
373 fprint(2, "too big; writing old tree back\n");
374 status = "cd too big; aborted";
375
376 rmdumpdir(&idumproot, dumpname);
377 rmdumpdir(&jdumproot, dumpname);
378
379 cd->nextblock = cd->nulldump+1;
380 cd->nulldump = 0;
381 Cwseek(cd, (vlong)cd->nextblock * Blocksize);
382 goto Dofix;
383 }
384
385 /*
386 * Write old null header block; this commits all our changes.
387 */
388 if(cd->nulldump){
389 Cwseek(cd, (vlong)cd->nulldump * Blocksize);
390 sprint(buf, "plan 9 dump cd\n");
391 sprint(buf+strlen(buf), "%s %lud %lud %lud %llud %lud %lud",
392 dumpname, now, newnull, cblock, clength,
393 iroot.block, iroot.length);
394 if(cd->flags & CDjoliet)
395 sprint(buf+strlen(buf), " %lud %lud",
396 jroot.block, jroot.length);
397 strcat(buf, "\n");
398 Cwrite(cd, buf, strlen(buf));
399 Cpadblock(cd);
400 Cwflush(cd);
401 }
402 }
403 fdtruncate(cd->fd, (vlong)cd->nextblock * Blocksize);
404 exits(status);
405 }
406
407 static void
addprotofile(char * new,char * old,Dir * d,void * a)408 addprotofile(char *new, char *old, Dir *d, void *a)
409 {
410 char *name, *p;
411 Direc *direc;
412 XDir xd;
413
414 dirtoxdir(&xd, d);
415 name = nil;
416 if(docolon && strchr(new, ':')) {
417 name = emalloc(strlen(new)+1);
418 strcpy(name, new);
419 while((p=strchr(name, ':')))
420 *p=' ';
421 new = name;
422 }
423 if((direc = adddirec((Direc*)a, new, &xd))) {
424 direc->srcfile = atom(old);
425
426 // BUG: abstract, biblio, notice
427 }
428 if(name)
429 free(name);
430 }
431