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