xref: /plan9/sys/src/cmd/cdfs/main.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
6 #include <9p.h>
7 #include <disk.h>
8 #include "dat.h"
9 #include "fns.h"
10 
11 static void checktoc(Drive*);
12 
13 int vflag;
14 
15 Drive *drive;
16 int nchange;
17 
18 enum {
19 	Qdir = 0|CHDIR,
20 	Qctl = 0,
21 	Qwa = 1|CHDIR,
22 	Qwd = 2|CHDIR,
23 	Qtrack = 3,
24 };
25 
26 char*
27 geterrstr(void)
28 {
29 	static char errbuf[ERRLEN];
30 
31 	errbuf[0] = 0;
32 	errstr(errbuf);
33 	return errbuf;
34 }
35 
36 void*
37 emalloc(ulong sz)
38 {
39 	void *v;
40 
41 	v = malloc(sz);
42 	if(v == nil)
43 		sysfatal("malloc %lud fails\n", sz);
44 	memset(v, 0, sz);
45 	return v;
46 }
47 
48 static void
49 cdattach(Req *r, Fid*, char *spec, Qid *qid)
50 {
51 	if(spec && spec[0]) {
52 		respond(r, "invalid attach specifier");
53 		return;
54 	}
55 
56 	checktoc(drive);
57 	*qid = (Qid){Qdir, drive->nchange};
58 	respond(r, nil);
59 }
60 
61 static void
62 cdclone(Req *r, Fid *old, Fid *new)
63 {
64 	Otrack *aux;
65 
66 	if(aux = old->aux)
67 		aux->nref++;
68 	new->aux = aux;
69 
70 	respond(r, nil);
71 }
72 
73 static void
74 cdwalk(Req *r, Fid *fid, char *name, Qid *qid)
75 {
76 	int i;
77 
78 	checktoc(drive);
79 	switch(fid->qid.path) {
80 	case Qdir:
81 		if(strcmp(name, "..") == 0) {
82 			*qid = (Qid){Qdir, drive->nchange};
83 			respond(r, nil);
84 			return;
85 		}
86 		if(strcmp(name, "ctl") == 0) {
87 			*qid = (Qid){Qctl, 0};
88 			respond(r, nil);
89 			return;
90 		}
91 		if(strcmp(name, "wa") == 0 && drive->writeok) {
92 			*qid = (Qid){Qwa, drive->nchange};
93 			respond(r, nil);
94 			return;
95 		}
96 		if(strcmp(name, "wd") == 0 && drive->writeok) {
97 			*qid = (Qid){Qwd, drive->nchange};
98 			respond(r, nil);
99 			return;
100 		}
101 		for(i=0; i<drive->ntrack; i++)
102 			if(strcmp(drive->track[i].name, name) == 0)
103 				break;
104 		if(i == drive->ntrack) {
105 			respond(r, "file not found");
106 			return;
107 		}
108 		*qid = (Qid){Qtrack+i, 0};
109 		respond(r, nil);
110 		return;
111 
112 	case Qwa:
113 	case Qwd:
114 		if(strcmp(name, "..") == 0) {
115 			*qid = (Qid){Qdir, drive->nchange};
116 			respond(r, nil);
117 			return;
118 		}
119 		respond(r, "file not found");
120 		return;
121 	default:	/* bug: lib9p could handle this */
122 		respond(r, "walk in non-directory");
123 		return;
124 	}
125 }
126 
127 static void
128 cdcreate(Req *r, Fid *fid, char*, int omode, ulong, Qid *qid)
129 {
130 	int type;
131 	Otrack *o;
132 
133 	if(omode != OWRITE) {
134 		respond(r, "bad mode (use OWRITE)");
135 		return;
136 	}
137 
138 	switch(fid->qid.path) {
139 	case Qdir:
140 	default:
141 		respond(r, "permission denied");
142 		return;
143 
144 	case Qwa:
145 		type = TypeAudio;
146 		break;
147 
148 	case Qwd:
149 		type = TypeData;
150 		break;
151 	}
152 
153 	if((drive->cap & Cwrite) == 0) {
154 		respond(r, "drive does not write");
155 		return;
156 	}
157 
158 	o = drive->create(drive, type);
159 	if(o == nil) {
160 		respond(r, geterrstr());
161 		return;
162 	}
163 	drive->nchange = -1;
164 	checktoc(drive);	/* update directory info */
165 	o->nref = 1;
166 	fid->aux = o;
167 
168 	*qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange};
169 	respond(r, nil);
170 }
171 
172 static void
173 cdremove(Req *r, Fid *fid)
174 {
175 	switch(fid->qid.path){
176 	case Qwa:
177 	case Qwd:
178 		if(drive->fixate(drive) < 0)
179 			respond(r, geterrstr());
180 // let's see if it can figure this out		drive->writeok = 0;
181 		else
182 			respond(r, nil);
183 		checktoc(drive);
184 		break;
185 	default:
186 		respond(r, "permission denied");
187 		break;
188 	}
189 }
190 
191 int
192 fillstat(int qid, Dir *d)
193 {
194 	Track *t;
195 
196 	memset(d, 0, sizeof(Dir));
197 	strcpy(d->uid, "cd");
198 	strcpy(d->gid, "cd");
199 	d->qid = (Qid){qid, drive->nchange};
200 	d->atime = time(0);
201 	d->mtime = drive->changetime;
202 
203 	switch(qid){
204 	case Qdir:
205 		strcpy(d->name, "/");
206 		d->mode = CHDIR|0777;
207 		break;
208 
209 	case Qctl:
210 		strcpy(d->name, "ctl");
211 		d->mode = 0666;
212 		break;
213 
214 	case Qwa&~CHDIR:
215 	case Qwa:
216 		if(drive->writeok == 0)
217 			return 0;
218 		strcpy(d->name, "wa");
219 		d->mode = CHDIR|0777;
220 		break;
221 
222 	case Qwd&~CHDIR:
223 	case Qwd:
224 		if(drive->writeok == 0)
225 			return 0;
226 		strcpy(d->name, "wd");
227 		d->mode = CHDIR|0777;
228 		break;
229 
230 	default:
231 		if(qid-Qtrack >= drive->ntrack)
232 			return 0;
233 		t = &drive->track[qid-Qtrack];
234 		if(strcmp(t->name, "") == 0)
235 			return 0;
236 		strcpy(d->name, t->name);
237 		d->mode = t->mode;
238 		d->length = t->size;
239 		break;
240 	}
241 	return 1;
242 }
243 
244 static int
245 readctl(void*, long, long)
246 {
247 	return 0;
248 }
249 
250 static void
251 cdread(Req *r, Fid *fid, void *buf, long *count, vlong offset)
252 {
253 	int i, j, off, n, m;
254 	char *p;
255 	Dir d;
256 	Otrack *o;
257 
258 	switch(fid->qid.path) {
259 	case Qdir:
260 		checktoc(drive);
261 		p = buf;
262 		m = Qtrack+drive->ntrack;
263 		n = *count/DIRLEN;
264 		off = offset/DIRLEN;
265 		for(i=0, j=0; j<m && i<off+n; j++) {
266 			if(fillstat(j, &d)) {
267 				if(off<=i && i<off+n) {
268 					convD2M(&d, p);
269 					p += DIRLEN;
270 				}
271 				i++;
272 			}
273 		}
274 		*count = (i-off)*DIRLEN;
275 		respond(r, nil);
276 		return;
277 
278 	case Qwa:
279 	case Qwd:
280 		*count = 0;
281 		respond(r, nil);
282 		return;
283 
284 	case Qctl:
285 		*count = readctl(buf, *count, offset);
286 		respond(r, nil);
287 		return;
288 	}
289 
290 	/* a disk track; we can only call read for whole blocks */
291 	o = fid->aux;
292 
293 	if((*count = o->drive->read(o, buf, *count, offset)) < 0)
294 		respond(r, geterrstr());
295 	else
296 		respond(r, nil);
297 
298 	return;
299 }
300 
301 static char*
302 writectl(void *v, long count)
303 {
304 	char buf[256];
305 	char *f[10];
306 	int nf;
307 
308 	if(count >= sizeof(buf))
309 		count = sizeof(buf)-1;
310 	memmove(buf, v, count);
311 	buf[count] = '\0';
312 
313 	nf = tokenize(buf, f, nelem(f));
314 	return drive->ctl(drive, nf, f);
315 }
316 
317 static void
318 cdwrite(Req *r, Fid *fid, void *buf, long *count, vlong)
319 {
320 	Otrack *o;
321 
322 	if(fid->qid.path == Qctl) {
323 		respond(r, writectl(buf, *count));
324 		return;
325 	}
326 
327 	if((o = fid->aux) == nil || o->omode != OWRITE) {
328 		respond(r, "permission denied");
329 		return;
330 	}
331 
332 	if(o->drive->write(o, buf, *count) < 0)
333 		respond(r, geterrstr());
334 	else
335 		respond(r, nil);
336 }
337 
338 static void
339 cdstat(Req *r, Fid *fid, Dir *d)
340 {
341 	fillstat(fid->qid.path, d);
342 	respond(r, nil);
343 }
344 
345 static void
346 cdopen(Req *r, Fid *fid, int omode, Qid *qid)
347 {
348 	Otrack *o;
349 
350 	checktoc(drive);
351 	*qid = (Qid){fid->qid.path, drive->nchange};
352 
353 	switch(fid->qid.path){
354 	case Qdir:
355 	case Qwa:
356 	case Qwd:
357 		if(omode == OREAD)
358 			respond(r, nil);
359 		else
360 			respond(r, "permission denied");
361 		return;
362 
363 	case Qctl:
364 		if(omode&~(OTRUNC|OREAD|OWRITE|ORDWR))
365 			respond(r, "permission denied");
366 		else
367 			respond(r, nil);
368 		return;
369 
370 	default:
371 		if(fid->qid.path >= Qtrack+drive->ntrack) {
372 			respond(r, "file no longer exists");
373 			return;
374 		}
375 
376 		if(omode != OREAD || (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
377 			respond(r, "permission denied");
378 			return;
379 		}
380 
381 		o->nref = 1;
382 		fid->aux = o;
383 		respond(r, nil);
384 	}
385 }
386 
387 static uchar zero[BScdda];
388 
389 static void
390 cdclunkaux(Fid *fid)
391 {
392 	Otrack *o;
393 
394 	o = fid->aux;
395 	if(o && --o->nref == 0) {
396 		bterm(o->buf);
397 		drive->close(o);
398 		checktoc(drive);
399 	}
400 }
401 
402 static void
403 checktoc(Drive *drive)
404 {
405 	int i;
406 	Track *t;
407 
408 	drive->gettoc(drive);
409 	if(drive->nameok)
410 		return;
411 
412 	for(i=0; i<drive->ntrack; i++) {
413 		t = &drive->track[i];
414 		if(t->size == 0)	/* being created */
415 			t->mode = 0;
416 		else
417 			t->mode = 0444;
418 		sprint(t->name, "?%.3d", i);
419 		switch(t->type){
420 		case TypeNone:
421 			t->name[0] = 'u';
422 			t->mode = 0;
423 			break;
424 		case TypeData:
425 			t->name[0] = 'd';
426 			break;
427 		case TypeAudio:
428 			t->name[0] = 'a';
429 			break;
430 		case TypeBlank:
431 			t->name[0] = '\0';
432 			break;
433 		default:
434 			print("unknown type %d\n", t->type);
435 			break;
436 		}
437 	}
438 
439 	drive->nameok = 1;
440 }
441 
442 long
443 bufread(Otrack *t, void *v, long n, long off)
444 {
445 	return bread(t->buf, v, n, off);
446 }
447 
448 long
449 bufwrite(Otrack *t, void *v, long n)
450 {
451 	return bwrite(t->buf, v, n);
452 }
453 
454 Srv cdsrv = {
455 .attach=	cdattach,
456 .clone=	cdclone,
457 .clunkaux=	cdclunkaux,
458 .walk=	cdwalk,
459 .open=	cdopen,
460 .read=	cdread,
461 .write=	cdwrite,
462 .create=	cdcreate,
463 .remove=	cdremove,
464 .stat=	cdstat,
465 };
466 
467 void
468 usage(void)
469 {
470 	fprint(2, "usage: cdfs [-v] [-d /dev/sdC0] [-m mtpt]\n");
471 	exits("usage");
472 }
473 
474 void
475 main(int argc, char **argv)
476 {
477 	Scsi *s;
478 	int fd;
479 	char *dev, *mtpt;
480 
481 	dev = "/dev/sdD0";
482 	mtpt = "/mnt/cd";
483 
484 	ARGBEGIN{
485 	case 'd':
486 		dev = ARGF();
487 		break;
488 	case 'm':
489 		mtpt = ARGF();
490 		break;
491 	case 'v':
492 		if((fd = create("/tmp/cdfs.log", OWRITE, 0666)) >= 0) {
493 			dup(fd, 2);
494 			dup(fd, 1);
495 			if(fd != 1 && fd != 2)
496 				close(fd);
497 			vflag++;
498 			scsiverbose++;
499 		}
500 		break;
501 	case 'V':
502 		lib9p_chatty++;
503 		break;
504 	default:
505 		usage();
506 	}ARGEND
507 
508 	if(dev == nil || mtpt == nil || argc > 0)
509 		usage();
510 
511 	if((s = openscsi(dev)) == nil) {
512 		fprint(2, "openscsi '%s': %r\n", dev);
513 		exits("openscsi");
514 	}
515 
516 	if((drive = mmcprobe(s)) == nil) {
517 		fprint(2, "mmcprobe '%s': %r\n", dev);
518 		exits("mmcprobe");
519 	}
520 
521 	checktoc(drive);
522 
523 	postmountsrv(&cdsrv, nil, mtpt, MREPL|MCREATE);
524 }
525