xref: /plan9/sys/src/cmd/cdfs/main.c (revision 889a2622ddfec1cddd31ce9ec338e8fabdc678ea)
1e67f3b95SDavid du Colombier /* cdfs - CD, DVD and BD reader and writer file system */
27dd7cddfSDavid du Colombier #include <u.h>
37dd7cddfSDavid du Colombier #include <libc.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <fcall.h>
67dd7cddfSDavid du Colombier #include <thread.h>
77dd7cddfSDavid du Colombier #include <9p.h>
87dd7cddfSDavid du Colombier #include <disk.h>
97dd7cddfSDavid du Colombier #include "dat.h"
107dd7cddfSDavid du Colombier #include "fns.h"
117dd7cddfSDavid du Colombier 
129a747e4fSDavid du Colombier typedef struct Aux Aux;
139a747e4fSDavid du Colombier struct Aux {
149a747e4fSDavid du Colombier 	int	doff;
159a747e4fSDavid du Colombier 	Otrack	*o;
169a747e4fSDavid du Colombier };
179a747e4fSDavid du Colombier 
188ad6bb6aSDavid du Colombier ulong	getnwa(Drive *);
198ad6bb6aSDavid du Colombier 
207dd7cddfSDavid du Colombier static void checktoc(Drive*);
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier int vflag;
237dd7cddfSDavid du Colombier 
24684b447eSDavid du Colombier static Drive *drive;
25684b447eSDavid du Colombier static int nchange;
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier enum {
289a747e4fSDavid du Colombier 	Qdir = 0,
299a747e4fSDavid du Colombier 	Qctl = 1,
309a747e4fSDavid du Colombier 	Qwa = 2,
319a747e4fSDavid du Colombier 	Qwd = 3,
329a747e4fSDavid du Colombier 	Qtrack = 4,
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier char*
geterrstr(void)367dd7cddfSDavid du Colombier geterrstr(void)
377dd7cddfSDavid du Colombier {
389a747e4fSDavid du Colombier 	static char errbuf[ERRMAX];
397dd7cddfSDavid du Colombier 
409a747e4fSDavid du Colombier 	rerrstr(errbuf, sizeof errbuf);
417dd7cddfSDavid du Colombier 	return errbuf;
427dd7cddfSDavid du Colombier }
437dd7cddfSDavid du Colombier 
4459cc4ca5SDavid du Colombier void*
emalloc(ulong sz)4559cc4ca5SDavid du Colombier emalloc(ulong sz)
4659cc4ca5SDavid du Colombier {
4759cc4ca5SDavid du Colombier 	void *v;
4859cc4ca5SDavid du Colombier 
49dd12a5c6SDavid du Colombier 	v = mallocz(sz, 1);
5059cc4ca5SDavid du Colombier 	if(v == nil)
5114cc0f53SDavid du Colombier 		sysfatal("malloc %lud fails", sz);
5259cc4ca5SDavid du Colombier 	return v;
5359cc4ca5SDavid du Colombier }
5459cc4ca5SDavid du Colombier 
557dd7cddfSDavid du Colombier static void
fsattach(Req * r)569a747e4fSDavid du Colombier fsattach(Req *r)
577dd7cddfSDavid du Colombier {
589a747e4fSDavid du Colombier 	char *spec;
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier 	spec = r->ifcall.aname;
617dd7cddfSDavid du Colombier 	if(spec && spec[0]) {
627dd7cddfSDavid du Colombier 		respond(r, "invalid attach specifier");
637dd7cddfSDavid du Colombier 		return;
647dd7cddfSDavid du Colombier 	}
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier 	checktoc(drive);
679a747e4fSDavid du Colombier 	r->fid->qid = (Qid){Qdir, drive->nchange, QTDIR};
689a747e4fSDavid du Colombier 	r->ofcall.qid = r->fid->qid;
699a747e4fSDavid du Colombier 	r->fid->aux = emalloc(sizeof(Aux));
707dd7cddfSDavid du Colombier 	respond(r, nil);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier 
739a747e4fSDavid du Colombier static char*
fsclone(Fid * old,Fid * new)749a747e4fSDavid du Colombier fsclone(Fid *old, Fid *new)
757dd7cddfSDavid du Colombier {
769a747e4fSDavid du Colombier 	Aux *na;
777dd7cddfSDavid du Colombier 
789a747e4fSDavid du Colombier 	na = emalloc(sizeof(Aux));
799a747e4fSDavid du Colombier 	*na = *((Aux*)old->aux);
809a747e4fSDavid du Colombier 	if(na->o)
819a747e4fSDavid du Colombier 		na->o->nref++;
829a747e4fSDavid du Colombier 	new->aux = na;
839a747e4fSDavid du Colombier 	return nil;
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier 
869a747e4fSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)879a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier 	int i;
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier 	checktoc(drive);
929a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path) {
937dd7cddfSDavid du Colombier 	case Qdir:
947dd7cddfSDavid du Colombier 		if(strcmp(name, "..") == 0) {
959a747e4fSDavid du Colombier 			*qid = (Qid){Qdir, drive->nchange, QTDIR};
969a747e4fSDavid du Colombier 			return nil;
977dd7cddfSDavid du Colombier 		}
987dd7cddfSDavid du Colombier 		if(strcmp(name, "ctl") == 0) {
999a747e4fSDavid du Colombier 			*qid = (Qid){Qctl, 0, 0};
1009a747e4fSDavid du Colombier 			return nil;
1017dd7cddfSDavid du Colombier 		}
102436f307dSDavid du Colombier 		if(strcmp(name, "wa") == 0 && drive->writeok &&
103cdf9e71cSDavid du Colombier 		    (drive->mmctype == Mmcnone ||
104cdf9e71cSDavid du Colombier 		     drive->mmctype == Mmccd)) {
1059a747e4fSDavid du Colombier 			*qid = (Qid){Qwa, drive->nchange, QTDIR};
1069a747e4fSDavid du Colombier 			return nil;
1077dd7cddfSDavid du Colombier 		}
1087dd7cddfSDavid du Colombier 		if(strcmp(name, "wd") == 0 && drive->writeok) {
1099a747e4fSDavid du Colombier 			*qid = (Qid){Qwd, drive->nchange, QTDIR};
1109a747e4fSDavid du Colombier 			return nil;
1117dd7cddfSDavid du Colombier 		}
1127dd7cddfSDavid du Colombier 		for(i=0; i<drive->ntrack; i++)
1137dd7cddfSDavid du Colombier 			if(strcmp(drive->track[i].name, name) == 0)
1147dd7cddfSDavid du Colombier 				break;
1158ad6bb6aSDavid du Colombier 		if(i == drive->ntrack)
1169a747e4fSDavid du Colombier 			return "file not found";
1179a747e4fSDavid du Colombier 		*qid = (Qid){Qtrack+i, 0, 0};
1189a747e4fSDavid du Colombier 		return nil;
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	case Qwa:
1217dd7cddfSDavid du Colombier 	case Qwd:
1227dd7cddfSDavid du Colombier 		if(strcmp(name, "..") == 0) {
1239a747e4fSDavid du Colombier 			*qid = (Qid){Qdir, drive->nchange, QTDIR};
1249a747e4fSDavid du Colombier 			return nil;
1257dd7cddfSDavid du Colombier 		}
1269a747e4fSDavid du Colombier 		return "file not found";
1277dd7cddfSDavid du Colombier 	default:	/* bug: lib9p could handle this */
1289a747e4fSDavid du Colombier 		return "walk in non-directory";
1297dd7cddfSDavid du Colombier 	}
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier static void
fscreate(Req * r)1339a747e4fSDavid du Colombier fscreate(Req *r)
1347dd7cddfSDavid du Colombier {
1359a747e4fSDavid du Colombier 	int omode, type;
1367dd7cddfSDavid du Colombier 	Otrack *o;
1379a747e4fSDavid du Colombier 	Fid *fid;
1389a747e4fSDavid du Colombier 
1399a747e4fSDavid du Colombier 	fid = r->fid;
1409a747e4fSDavid du Colombier 	omode = r->ifcall.mode;
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	if(omode != OWRITE) {
1437dd7cddfSDavid du Colombier 		respond(r, "bad mode (use OWRITE)");
1447dd7cddfSDavid du Colombier 		return;
1457dd7cddfSDavid du Colombier 	}
1467dd7cddfSDavid du Colombier 
1479a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path) {
1487dd7cddfSDavid du Colombier 	case Qdir:
1497dd7cddfSDavid du Colombier 	default:
1507dd7cddfSDavid du Colombier 		respond(r, "permission denied");
1517dd7cddfSDavid du Colombier 		return;
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier 	case Qwa:
154cdf9e71cSDavid du Colombier 		if (drive->mmctype != Mmcnone &&
155cdf9e71cSDavid du Colombier 		    drive->mmctype != Mmccd) {
156436f307dSDavid du Colombier 			respond(r, "audio supported only on cd");
157436f307dSDavid du Colombier 			return;
158436f307dSDavid du Colombier 		}
1597dd7cddfSDavid du Colombier 		type = TypeAudio;
1607dd7cddfSDavid du Colombier 		break;
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier 	case Qwd:
1637dd7cddfSDavid du Colombier 		type = TypeData;
1647dd7cddfSDavid du Colombier 		break;
1657dd7cddfSDavid du Colombier 	}
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 	if((drive->cap & Cwrite) == 0) {
1687dd7cddfSDavid du Colombier 		respond(r, "drive does not write");
1697dd7cddfSDavid du Colombier 		return;
1707dd7cddfSDavid du Colombier 	}
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	o = drive->create(drive, type);
1737dd7cddfSDavid du Colombier 	if(o == nil) {
1747dd7cddfSDavid du Colombier 		respond(r, geterrstr());
1757dd7cddfSDavid du Colombier 		return;
1767dd7cddfSDavid du Colombier 	}
1777dd7cddfSDavid du Colombier 	drive->nchange = -1;
1787dd7cddfSDavid du Colombier 	checktoc(drive);	/* update directory info */
1797dd7cddfSDavid du Colombier 	o->nref = 1;
1809a747e4fSDavid du Colombier 	((Aux*)fid->aux)->o = o;
1817dd7cddfSDavid du Colombier 
1829a747e4fSDavid du Colombier 	fid->qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange, 0};
1839a747e4fSDavid du Colombier 	r->ofcall.qid = fid->qid;
1847dd7cddfSDavid du Colombier 	respond(r, nil);
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier static void
fsremove(Req * r)1889a747e4fSDavid du Colombier fsremove(Req *r)
1897dd7cddfSDavid du Colombier {
1909a747e4fSDavid du Colombier 	switch((ulong)r->fid->qid.path){
1917dd7cddfSDavid du Colombier 	case Qwa:
1927dd7cddfSDavid du Colombier 	case Qwd:
1937dd7cddfSDavid du Colombier 		if(drive->fixate(drive) < 0)
1947dd7cddfSDavid du Colombier 			respond(r, geterrstr());
19560ba15acSDavid du Colombier // let us see if it can figure this out:	drive->writeok = No;
1967dd7cddfSDavid du Colombier 		else
1977dd7cddfSDavid du Colombier 			respond(r, nil);
1987dd7cddfSDavid du Colombier 		checktoc(drive);
1997dd7cddfSDavid du Colombier 		break;
2007dd7cddfSDavid du Colombier 	default:
2017dd7cddfSDavid du Colombier 		respond(r, "permission denied");
2027dd7cddfSDavid du Colombier 		break;
2037dd7cddfSDavid du Colombier 	}
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier 
2062d8b52e8SDavid du Colombier /* result is one word, so it can be used as a uid in Dir structs */
2072112d02cSDavid du Colombier char *
disctype(Drive * drive)208079e489fSDavid du Colombier disctype(Drive *drive)
209079e489fSDavid du Colombier {
210*889a2622SDavid du Colombier 	char *type, *rw, *laysfx;
211079e489fSDavid du Colombier 
212*889a2622SDavid du Colombier 	rw = laysfx = "";
213079e489fSDavid du Colombier 	switch (drive->mmctype) {
214079e489fSDavid du Colombier 	case Mmccd:
215079e489fSDavid du Colombier 		type = "cd-";
216079e489fSDavid du Colombier 		break;
217079e489fSDavid du Colombier 	case Mmcdvdminus:
218079e489fSDavid du Colombier 	case Mmcdvdplus:
219079e489fSDavid du Colombier 		type = drive->dvdtype;
220079e489fSDavid du Colombier 		break;
221079e489fSDavid du Colombier 	case Mmcbd:
222079e489fSDavid du Colombier 		type = "bd-";
223*889a2622SDavid du Colombier 		if (drive->laysfx)
224*889a2622SDavid du Colombier 			laysfx = drive->laysfx;
225079e489fSDavid du Colombier 		break;
226079e489fSDavid du Colombier 	case Mmcnone:
2272d8b52e8SDavid du Colombier 		type = "no-disc";
228079e489fSDavid du Colombier 		break;
229079e489fSDavid du Colombier 	default:
230079e489fSDavid du Colombier 		type = "**GOK**";		/* traditional */
231079e489fSDavid du Colombier 		break;
232079e489fSDavid du Colombier 	}
233079e489fSDavid du Colombier 	if (drive->mmctype != Mmcnone && drive->dvdtype == nil)
23460ba15acSDavid du Colombier 		if (drive->erasable == Yes)
23588a5d610SDavid du Colombier 			rw = drive->mmctype == Mmcbd? "re": "rw";
23660ba15acSDavid du Colombier 		else if (drive->recordable == Yes)
237079e489fSDavid du Colombier 			rw = "r";
238079e489fSDavid du Colombier 		else
239079e489fSDavid du Colombier 			rw = "rom";
240*889a2622SDavid du Colombier 	return smprint("%s%s%s", type, rw, laysfx);
241079e489fSDavid du Colombier }
242079e489fSDavid du Colombier 
2437dd7cddfSDavid du Colombier int
fillstat(ulong qid,Dir * d)2449a747e4fSDavid du Colombier fillstat(ulong qid, Dir *d)
2457dd7cddfSDavid du Colombier {
246079e489fSDavid du Colombier 	char *ty;
2477dd7cddfSDavid du Colombier 	Track *t;
248079e489fSDavid du Colombier 	static char buf[32];
2497dd7cddfSDavid du Colombier 
250e67f3b95SDavid du Colombier 	nulldir(d);
251e67f3b95SDavid du Colombier 	d->type = L'M';
252e67f3b95SDavid du Colombier 	d->dev = 1;
253e67f3b95SDavid du Colombier 	d->length = 0;
254079e489fSDavid du Colombier 	ty = disctype(drive);
255079e489fSDavid du Colombier 	strncpy(buf, ty, sizeof buf);
256079e489fSDavid du Colombier 	free(ty);
257079e489fSDavid du Colombier 	d->uid = d->gid = buf;
2589a747e4fSDavid du Colombier 	d->muid = "";
2599a747e4fSDavid du Colombier 	d->qid = (Qid){qid, drive->nchange, 0};
2607dd7cddfSDavid du Colombier 	d->atime = time(0);
261e67f3b95SDavid du Colombier 	d->mtime = drive->changetime;
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier 	switch(qid){
2647dd7cddfSDavid du Colombier 	case Qdir:
2659a747e4fSDavid du Colombier 		d->name = "/";
2669a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2679a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
2687dd7cddfSDavid du Colombier 		break;
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	case Qctl:
2719a747e4fSDavid du Colombier 		d->name = "ctl";
2727dd7cddfSDavid du Colombier 		d->mode = 0666;
2737dd7cddfSDavid du Colombier 		break;
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier 	case Qwa:
27660ba15acSDavid du Colombier 		if(drive->writeok == No ||
277cdf9e71cSDavid du Colombier 		    drive->mmctype != Mmcnone &&
278cdf9e71cSDavid du Colombier 		    drive->mmctype != Mmccd)
2797dd7cddfSDavid du Colombier 			return 0;
2809a747e4fSDavid du Colombier 		d->name = "wa";
2819a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2829a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
2837dd7cddfSDavid du Colombier 		break;
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	case Qwd:
28660ba15acSDavid du Colombier 		if(drive->writeok == No)
2877dd7cddfSDavid du Colombier 			return 0;
2889a747e4fSDavid du Colombier 		d->name = "wd";
2899a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2909a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
2917dd7cddfSDavid du Colombier 		break;
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	default:
2947dd7cddfSDavid du Colombier 		if(qid-Qtrack >= drive->ntrack)
2957dd7cddfSDavid du Colombier 			return 0;
2967dd7cddfSDavid du Colombier 		t = &drive->track[qid-Qtrack];
2977dd7cddfSDavid du Colombier 		if(strcmp(t->name, "") == 0)
2987dd7cddfSDavid du Colombier 			return 0;
2999a747e4fSDavid du Colombier 		d->name = t->name;
3007dd7cddfSDavid du Colombier 		d->mode = t->mode;
3017dd7cddfSDavid du Colombier 		d->length = t->size;
3027dd7cddfSDavid du Colombier 		break;
3037dd7cddfSDavid du Colombier 	}
3047dd7cddfSDavid du Colombier 	return 1;
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier 
3079a747e4fSDavid du Colombier static ulong
cddb_sum(int n)3089a747e4fSDavid du Colombier cddb_sum(int n)
3097dd7cddfSDavid du Colombier {
3109a747e4fSDavid du Colombier 	int ret;
3119a747e4fSDavid du Colombier 	ret = 0;
3129a747e4fSDavid du Colombier 	while(n > 0) {
3139a747e4fSDavid du Colombier 		ret += n%10;
3149a747e4fSDavid du Colombier 		n /= 10;
3159a747e4fSDavid du Colombier 	}
3169a747e4fSDavid du Colombier 	return ret;
3179a747e4fSDavid du Colombier }
3189a747e4fSDavid du Colombier 
3199a747e4fSDavid du Colombier static ulong
diskid(Drive * d)3209a747e4fSDavid du Colombier diskid(Drive *d)
3219a747e4fSDavid du Colombier {
3229a747e4fSDavid du Colombier 	int i, n;
3239a747e4fSDavid du Colombier 	ulong tmp;
3249a747e4fSDavid du Colombier 	Msf *ms, *me;
3259a747e4fSDavid du Colombier 
3269a747e4fSDavid du Colombier 	n = 0;
3279a747e4fSDavid du Colombier 	for(i=0; i < d->ntrack; i++)
3289a747e4fSDavid du Colombier 		n += cddb_sum(d->track[i].mbeg.m*60+d->track[i].mbeg.s);
3299a747e4fSDavid du Colombier 
3309a747e4fSDavid du Colombier 	ms = &d->track[0].mbeg;
3319a747e4fSDavid du Colombier 	me = &d->track[d->ntrack].mbeg;
3329a747e4fSDavid du Colombier 	tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier 	/*
3358ad6bb6aSDavid du Colombier 	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is
3368ad6bb6aSDavid du Colombier 	 * correct.  most CDs are in the database under both entries.
3379a747e4fSDavid du Colombier 	 */
3389a747e4fSDavid du Colombier 	return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);
3397dd7cddfSDavid du Colombier }
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier static void
readctl(Req * r)3429a747e4fSDavid du Colombier readctl(Req *r)
3437dd7cddfSDavid du Colombier {
3449a747e4fSDavid du Colombier 	int i, isaudio;
345801be386SDavid du Colombier 	ulong nwa;
346079e489fSDavid du Colombier 	char *p, *e, *ty;
3479a747e4fSDavid du Colombier 	char s[1024];
3489a747e4fSDavid du Colombier 	Msf *m;
3497dd7cddfSDavid du Colombier 
3509a747e4fSDavid du Colombier 	isaudio = 0;
3519a747e4fSDavid du Colombier 	for(i=0; i<drive->ntrack; i++)
3529a747e4fSDavid du Colombier 		if(drive->track[i].type == TypeAudio)
3539a747e4fSDavid du Colombier 			isaudio = 1;
3549a747e4fSDavid du Colombier 
3558ad6bb6aSDavid du Colombier 	p = s;
3568ad6bb6aSDavid du Colombier 	e = s + sizeof s;
3578ad6bb6aSDavid du Colombier 	*p = '\0';
3589a747e4fSDavid du Colombier 	if(isaudio){
3598ad6bb6aSDavid du Colombier 		p = seprint(p, e, "aux/cddb query %8.8lux %d", diskid(drive),
3608ad6bb6aSDavid du Colombier 			drive->ntrack);
3619a747e4fSDavid du Colombier 		for(i=0; i<drive->ntrack; i++){
3629a747e4fSDavid du Colombier 			m = &drive->track[i].mbeg;
3638ad6bb6aSDavid du Colombier 			p = seprint(p, e, " %d", (m->m*60 + m->s)*75 + m->f);
3649a747e4fSDavid du Colombier 		}
3659a747e4fSDavid du Colombier 		m = &drive->track[drive->ntrack].mbeg;
3668ad6bb6aSDavid du Colombier 		p = seprint(p, e, " %d\n", m->m*60 + m->s);
3679a747e4fSDavid du Colombier 	}
3689a747e4fSDavid du Colombier 
3699a747e4fSDavid du Colombier 	if(drive->readspeed == drive->writespeed)
3708ad6bb6aSDavid du Colombier 		p = seprint(p, e, "speed %d\n", drive->readspeed);
3719a747e4fSDavid du Colombier 	else
3728ad6bb6aSDavid du Colombier 		p = seprint(p, e, "speed read %d write %d\n",
373cdf9e71cSDavid du Colombier 			drive->readspeed, drive->writespeed);
3748ad6bb6aSDavid du Colombier 	p = seprint(p, e, "maxspeed read %d write %d\n",
375cdf9e71cSDavid du Colombier 		drive->maxreadspeed, drive->maxwritespeed);
3768ad6bb6aSDavid du Colombier 
3778ad6bb6aSDavid du Colombier 	if (drive->Scsi.changetime != 0 && drive->ntrack != 0) { /* have disc? */
378079e489fSDavid du Colombier 		ty = disctype(drive);
379079e489fSDavid du Colombier 		p = seprint(p, e, "%s", ty);
380079e489fSDavid du Colombier 		free(ty);
381801be386SDavid du Colombier 		if (drive->mmctype != Mmcnone) {
382801be386SDavid du Colombier 			nwa = getnwa(drive);
383801be386SDavid du Colombier 			p = seprint(p, e, " next writable sector ");
384801be386SDavid du Colombier 			if (nwa == ~0ul)
385801be386SDavid du Colombier 				p = seprint(p, e, "none; disc full");
386801be386SDavid du Colombier 			else
387801be386SDavid du Colombier 				p = seprint(p, e, "%lud", nwa);
388801be386SDavid du Colombier 		}
3898ad6bb6aSDavid du Colombier 		seprint(p, e, "\n");
3908ad6bb6aSDavid du Colombier 	}
3919a747e4fSDavid du Colombier 	readstr(r, s);
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier 
3949a747e4fSDavid du Colombier static void
fsread(Req * r)3959a747e4fSDavid du Colombier fsread(Req *r)
3969a747e4fSDavid du Colombier {
3979a747e4fSDavid du Colombier 	int j, n, m;
3989a747e4fSDavid du Colombier 	uchar *p, *ep;
3999a747e4fSDavid du Colombier 	Dir d;
4009a747e4fSDavid du Colombier 	Fid *fid;
4019a747e4fSDavid du Colombier 	Otrack *o;
4029a747e4fSDavid du Colombier 	vlong offset;
4039a747e4fSDavid du Colombier 	void *buf;
4049a747e4fSDavid du Colombier 	long count;
4059a747e4fSDavid du Colombier 	Aux *a;
4069a747e4fSDavid du Colombier 
4079a747e4fSDavid du Colombier 	fid = r->fid;
4089a747e4fSDavid du Colombier 	offset = r->ifcall.offset;
4099a747e4fSDavid du Colombier 	buf = r->ofcall.data;
4109a747e4fSDavid du Colombier 	count = r->ifcall.count;
4119a747e4fSDavid du Colombier 
4129a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path) {
4137dd7cddfSDavid du Colombier 	case Qdir:
4147dd7cddfSDavid du Colombier 		checktoc(drive);
4157dd7cddfSDavid du Colombier 		p = buf;
4169a747e4fSDavid du Colombier 		ep = p+count;
4177dd7cddfSDavid du Colombier 		m = Qtrack+drive->ntrack;
4189a747e4fSDavid du Colombier 		a = fid->aux;
4199a747e4fSDavid du Colombier 		if(offset == 0)
4209a747e4fSDavid du Colombier 			a->doff = 1;	/* skip root */
4219a747e4fSDavid du Colombier 
4229a747e4fSDavid du Colombier 		for(j=a->doff; j<m; j++) {
4237dd7cddfSDavid du Colombier 			if(fillstat(j, &d)) {
4249a747e4fSDavid du Colombier 				if((n = convD2M(&d, p, ep-p)) <= BIT16SZ)
4259a747e4fSDavid du Colombier 					break;
4269a747e4fSDavid du Colombier 				p += n;
4277dd7cddfSDavid du Colombier 			}
4287dd7cddfSDavid du Colombier 		}
4299a747e4fSDavid du Colombier 		a->doff = j;
4309a747e4fSDavid du Colombier 
4319a747e4fSDavid du Colombier 		r->ofcall.count = p - (uchar*)buf;
432cdf9e71cSDavid du Colombier 		break;
4337dd7cddfSDavid du Colombier 	case Qwa:
4347dd7cddfSDavid du Colombier 	case Qwd:
4359a747e4fSDavid du Colombier 		r->ofcall.count = 0;
436cdf9e71cSDavid du Colombier 		break;
4377dd7cddfSDavid du Colombier 	case Qctl:
4389a747e4fSDavid du Colombier 		readctl(r);
439cdf9e71cSDavid du Colombier 		break;
440cdf9e71cSDavid du Colombier 	default:
4417dd7cddfSDavid du Colombier 		/* a disk track; we can only call read for whole blocks */
4429a747e4fSDavid du Colombier 		o = ((Aux*)fid->aux)->o;
443cdf9e71cSDavid du Colombier 		if((count = o->drive->read(o, buf, count, offset)) < 0) {
4447dd7cddfSDavid du Colombier 			respond(r, geterrstr());
445cdf9e71cSDavid du Colombier 			return;
4469a747e4fSDavid du Colombier 		}
447cdf9e71cSDavid du Colombier 		r->ofcall.count = count;
448cdf9e71cSDavid du Colombier 		break;
449cdf9e71cSDavid du Colombier 	}
450cdf9e71cSDavid du Colombier 	respond(r, nil);
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier 
453055c7668SDavid du Colombier static char Ebadmsg[] = "bad cdfs control message";
454c038c065SDavid du Colombier 
4557dd7cddfSDavid du Colombier static char*
writectl(void * v,long count)4567dd7cddfSDavid du Colombier writectl(void *v, long count)
4577dd7cddfSDavid du Colombier {
4587dd7cddfSDavid du Colombier 	char buf[256];
4599a747e4fSDavid du Colombier 	char *f[10], *p;
4609a747e4fSDavid du Colombier 	int i, nf, n, r, w, what;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	if(count >= sizeof(buf))
4637dd7cddfSDavid du Colombier 		count = sizeof(buf)-1;
4647dd7cddfSDavid du Colombier 	memmove(buf, v, count);
4657dd7cddfSDavid du Colombier 	buf[count] = '\0';
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	nf = tokenize(buf, f, nelem(f));
4689a747e4fSDavid du Colombier 	if(nf == 0)
4699a747e4fSDavid du Colombier 		return Ebadmsg;
4709a747e4fSDavid du Colombier 
4719a747e4fSDavid du Colombier 	if(strcmp(f[0], "speed") == 0){
4729a747e4fSDavid du Colombier 		what = 0;
4739a747e4fSDavid du Colombier 		r = w = -1;
4749a747e4fSDavid du Colombier 		if(nf == 1)
4759a747e4fSDavid du Colombier 			return Ebadmsg;
4769a747e4fSDavid du Colombier 		for(i=1; i<nf; i++){
4779a747e4fSDavid du Colombier 			if(strcmp(f[i], "read") == 0 || strcmp(f[i], "write") == 0){
4789a747e4fSDavid du Colombier 				if(what!=0 && what!='?')
4799a747e4fSDavid du Colombier 					return Ebadmsg;
4809a747e4fSDavid du Colombier 				what = f[i][0];
4819a747e4fSDavid du Colombier 			}else{
482055c7668SDavid du Colombier 				if (strcmp(f[i], "best") == 0)
483055c7668SDavid du Colombier 					n = (1<<16) - 1;
484055c7668SDavid du Colombier 				else {
4859a747e4fSDavid du Colombier 					n = strtol(f[i], &p, 0);
4869a747e4fSDavid du Colombier 					if(*p != '\0' || n <= 0)
4879a747e4fSDavid du Colombier 						return Ebadmsg;
488055c7668SDavid du Colombier 				}
4899a747e4fSDavid du Colombier 				switch(what){
4909a747e4fSDavid du Colombier 				case 0:
4919a747e4fSDavid du Colombier 					if(r >= 0 || w >= 0)
4929a747e4fSDavid du Colombier 						return Ebadmsg;
4939a747e4fSDavid du Colombier 					r = w = n;
4949a747e4fSDavid du Colombier 					break;
4959a747e4fSDavid du Colombier 				case 'r':
4969a747e4fSDavid du Colombier 					if(r >= 0)
4979a747e4fSDavid du Colombier 						return Ebadmsg;
4989a747e4fSDavid du Colombier 					r = n;
4999a747e4fSDavid du Colombier 					break;
5009a747e4fSDavid du Colombier 				case 'w':
5019a747e4fSDavid du Colombier 					if(w >= 0)
5029a747e4fSDavid du Colombier 						return Ebadmsg;
5039a747e4fSDavid du Colombier 					w = n;
5049a747e4fSDavid du Colombier 					break;
5059a747e4fSDavid du Colombier 				default:
5069a747e4fSDavid du Colombier 					return Ebadmsg;
5079a747e4fSDavid du Colombier 				}
508cdf9e71cSDavid du Colombier 				what = '?';
5099a747e4fSDavid du Colombier 			}
5109a747e4fSDavid du Colombier 		}
5119a747e4fSDavid du Colombier 		if(what != '?')
5129a747e4fSDavid du Colombier 			return Ebadmsg;
5139a747e4fSDavid du Colombier 		return drive->setspeed(drive, r, w);
5149a747e4fSDavid du Colombier 	}
5157dd7cddfSDavid du Colombier 	return drive->ctl(drive, nf, f);
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier 
5187dd7cddfSDavid du Colombier static void
fswrite(Req * r)5199a747e4fSDavid du Colombier fswrite(Req *r)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier 	Otrack *o;
5229a747e4fSDavid du Colombier 	Fid *fid;
5237dd7cddfSDavid du Colombier 
5249a747e4fSDavid du Colombier 	fid = r->fid;
5259a747e4fSDavid du Colombier 	r->ofcall.count = r->ifcall.count;
5267dd7cddfSDavid du Colombier 	if(fid->qid.path == Qctl) {
5279a747e4fSDavid du Colombier 		respond(r, writectl(r->ifcall.data, r->ifcall.count));
5287dd7cddfSDavid du Colombier 		return;
5297dd7cddfSDavid du Colombier 	}
5307dd7cddfSDavid du Colombier 
5319a747e4fSDavid du Colombier 	if((o = ((Aux*)fid->aux)->o) == nil || o->omode != OWRITE) {
5327dd7cddfSDavid du Colombier 		respond(r, "permission denied");
5337dd7cddfSDavid du Colombier 		return;
5347dd7cddfSDavid du Colombier 	}
5357dd7cddfSDavid du Colombier 
5369a747e4fSDavid du Colombier 	if(o->drive->write(o, r->ifcall.data, r->ifcall.count) < 0)
5377dd7cddfSDavid du Colombier 		respond(r, geterrstr());
5387dd7cddfSDavid du Colombier 	else
5397dd7cddfSDavid du Colombier 		respond(r, nil);
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier 
5427dd7cddfSDavid du Colombier static void
fsstat(Req * r)5439a747e4fSDavid du Colombier fsstat(Req *r)
5447dd7cddfSDavid du Colombier {
5459a747e4fSDavid du Colombier 	fillstat((ulong)r->fid->qid.path, &r->d);
5469a747e4fSDavid du Colombier 	r->d.name = estrdup9p(r->d.name);
5479a747e4fSDavid du Colombier 	r->d.uid = estrdup9p(r->d.uid);
5489a747e4fSDavid du Colombier 	r->d.gid = estrdup9p(r->d.gid);
5499a747e4fSDavid du Colombier 	r->d.muid = estrdup9p(r->d.muid);
5507dd7cddfSDavid du Colombier 	respond(r, nil);
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier static void
fsopen(Req * r)5549a747e4fSDavid du Colombier fsopen(Req *r)
5557dd7cddfSDavid du Colombier {
5569a747e4fSDavid du Colombier 	int omode;
5579a747e4fSDavid du Colombier 	Fid *fid;
5587dd7cddfSDavid du Colombier 	Otrack *o;
5597dd7cddfSDavid du Colombier 
5609a747e4fSDavid du Colombier 	fid = r->fid;
5619a747e4fSDavid du Colombier 	omode = r->ifcall.mode;
5627dd7cddfSDavid du Colombier 	checktoc(drive);
5639a747e4fSDavid du Colombier 	r->ofcall.qid = (Qid){fid->qid.path, drive->nchange, fid->qid.vers};
5647dd7cddfSDavid du Colombier 
5659a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path){
5667dd7cddfSDavid du Colombier 	case Qdir:
5677dd7cddfSDavid du Colombier 	case Qwa:
5687dd7cddfSDavid du Colombier 	case Qwd:
569cdf9e71cSDavid du Colombier 		if(omode != OREAD) {
5707dd7cddfSDavid du Colombier 			respond(r, "permission denied");
5717dd7cddfSDavid du Colombier 			return;
572cdf9e71cSDavid du Colombier 		}
573cdf9e71cSDavid du Colombier 		break;
5747dd7cddfSDavid du Colombier 	case Qctl:
575cdf9e71cSDavid du Colombier 		if(omode & ~(OTRUNC|OREAD|OWRITE|ORDWR)) {
5767dd7cddfSDavid du Colombier 			respond(r, "permission denied");
5777dd7cddfSDavid du Colombier 			return;
578cdf9e71cSDavid du Colombier 		}
579cdf9e71cSDavid du Colombier 		break;
5807dd7cddfSDavid du Colombier 	default:
5817dd7cddfSDavid du Colombier 		if(fid->qid.path >= Qtrack+drive->ntrack) {
5827dd7cddfSDavid du Colombier 			respond(r, "file no longer exists");
5837dd7cddfSDavid du Colombier 			return;
5847dd7cddfSDavid du Colombier 		}
5857dd7cddfSDavid du Colombier 
586c038c065SDavid du Colombier 		/*
587c038c065SDavid du Colombier 		 * allow the open with OWRITE or ORDWR if the
588c038c065SDavid du Colombier 		 * drive and disc are both capable?
589c038c065SDavid du Colombier 		 */
590c038c065SDavid du Colombier 		if(omode != OREAD ||
591c038c065SDavid du Colombier 		    (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
5927dd7cddfSDavid du Colombier 			respond(r, "permission denied");
5937dd7cddfSDavid du Colombier 			return;
5947dd7cddfSDavid du Colombier 		}
5957dd7cddfSDavid du Colombier 
5967dd7cddfSDavid du Colombier 		o->nref = 1;
5979a747e4fSDavid du Colombier 		((Aux*)fid->aux)->o = o;
598c038c065SDavid du Colombier 		break;
5997dd7cddfSDavid du Colombier 	}
600cdf9e71cSDavid du Colombier 	respond(r, nil);
6017dd7cddfSDavid du Colombier }
6027dd7cddfSDavid du Colombier 
6037dd7cddfSDavid du Colombier static void
fsdestroyfid(Fid * fid)6049a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
6057dd7cddfSDavid du Colombier {
6069a747e4fSDavid du Colombier 	Aux *aux;
6077dd7cddfSDavid du Colombier 	Otrack *o;
6087dd7cddfSDavid du Colombier 
6099a747e4fSDavid du Colombier 	aux = fid->aux;
6109a747e4fSDavid du Colombier 	if(aux == nil)
6119a747e4fSDavid du Colombier 		return;
6129a747e4fSDavid du Colombier 	o = aux->o;
6137dd7cddfSDavid du Colombier 	if(o && --o->nref == 0) {
6147dd7cddfSDavid du Colombier 		bterm(o->buf);
6157dd7cddfSDavid du Colombier 		drive->close(o);
6167dd7cddfSDavid du Colombier 		checktoc(drive);
6177dd7cddfSDavid du Colombier 	}
6187dd7cddfSDavid du Colombier }
6197dd7cddfSDavid du Colombier 
6207dd7cddfSDavid du Colombier static void
checktoc(Drive * drive)6217dd7cddfSDavid du Colombier checktoc(Drive *drive)
6227dd7cddfSDavid du Colombier {
6237dd7cddfSDavid du Colombier 	int i;
6247dd7cddfSDavid du Colombier 	Track *t;
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier 	drive->gettoc(drive);
6277dd7cddfSDavid du Colombier 	if(drive->nameok)
6287dd7cddfSDavid du Colombier 		return;
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier 	for(i=0; i<drive->ntrack; i++) {
6317dd7cddfSDavid du Colombier 		t = &drive->track[i];
6327dd7cddfSDavid du Colombier 		if(t->size == 0)	/* being created */
6337dd7cddfSDavid du Colombier 			t->mode = 0;
6347dd7cddfSDavid du Colombier 		else
6357dd7cddfSDavid du Colombier 			t->mode = 0444;
6367dd7cddfSDavid du Colombier 		sprint(t->name, "?%.3d", i);
6377dd7cddfSDavid du Colombier 		switch(t->type){
6387dd7cddfSDavid du Colombier 		case TypeNone:
6397dd7cddfSDavid du Colombier 			t->name[0] = 'u';
640e67f3b95SDavid du Colombier //			t->mode = 0;
6417dd7cddfSDavid du Colombier 			break;
6427dd7cddfSDavid du Colombier 		case TypeData:
6437dd7cddfSDavid du Colombier 			t->name[0] = 'd';
6447dd7cddfSDavid du Colombier 			break;
6457dd7cddfSDavid du Colombier 		case TypeAudio:
6467dd7cddfSDavid du Colombier 			t->name[0] = 'a';
6477dd7cddfSDavid du Colombier 			break;
6487dd7cddfSDavid du Colombier 		case TypeBlank:
6497dd7cddfSDavid du Colombier 			t->name[0] = '\0';
6507dd7cddfSDavid du Colombier 			break;
6517dd7cddfSDavid du Colombier 		default:
652079e489fSDavid du Colombier 			print("unknown track type %d\n", t->type);
6537dd7cddfSDavid du Colombier 			break;
6547dd7cddfSDavid du Colombier 		}
6557dd7cddfSDavid du Colombier 	}
6567dd7cddfSDavid du Colombier 
6577dd7cddfSDavid du Colombier 	drive->nameok = 1;
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier long
bufread(Otrack * t,void * v,long n,vlong off)661dd12a5c6SDavid du Colombier bufread(Otrack *t, void *v, long n, vlong off)
6627dd7cddfSDavid du Colombier {
6637dd7cddfSDavid du Colombier 	return bread(t->buf, v, n, off);
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier 
6667dd7cddfSDavid du Colombier long
bufwrite(Otrack * t,void * v,long n)6677dd7cddfSDavid du Colombier bufwrite(Otrack *t, void *v, long n)
6687dd7cddfSDavid du Colombier {
6697dd7cddfSDavid du Colombier 	return bwrite(t->buf, v, n);
6707dd7cddfSDavid du Colombier }
6717dd7cddfSDavid du Colombier 
6729a747e4fSDavid du Colombier Srv fs = {
6739a747e4fSDavid du Colombier .attach=	fsattach,
6749a747e4fSDavid du Colombier .destroyfid=	fsdestroyfid,
6759a747e4fSDavid du Colombier .clone=		fsclone,
6769a747e4fSDavid du Colombier .walk1=		fswalk1,
6779a747e4fSDavid du Colombier .open=		fsopen,
6789a747e4fSDavid du Colombier .read=		fsread,
6799a747e4fSDavid du Colombier .write=		fswrite,
6809a747e4fSDavid du Colombier .create=	fscreate,
6819a747e4fSDavid du Colombier .remove=	fsremove,
6829a747e4fSDavid du Colombier .stat=		fsstat,
6837dd7cddfSDavid du Colombier };
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier void
usage(void)6867dd7cddfSDavid du Colombier usage(void)
6877dd7cddfSDavid du Colombier {
6889a747e4fSDavid du Colombier 	fprint(2, "usage: cdfs [-Dv] [-d /dev/sdC0] [-m mtpt]\n");
6897dd7cddfSDavid du Colombier 	exits("usage");
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier 
6927dd7cddfSDavid du Colombier void
main(int argc,char ** argv)6937dd7cddfSDavid du Colombier main(int argc, char **argv)
6947dd7cddfSDavid du Colombier {
6957dd7cddfSDavid du Colombier 	Scsi *s;
6967dd7cddfSDavid du Colombier 	int fd;
6977dd7cddfSDavid du Colombier 	char *dev, *mtpt;
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier 	dev = "/dev/sdD0";
7007dd7cddfSDavid du Colombier 	mtpt = "/mnt/cd";
7017dd7cddfSDavid du Colombier 
7027dd7cddfSDavid du Colombier 	ARGBEGIN{
7039a747e4fSDavid du Colombier 	case 'D':
7049a747e4fSDavid du Colombier 		chatty9p++;
7059a747e4fSDavid du Colombier 		break;
7067dd7cddfSDavid du Colombier 	case 'd':
707e67f3b95SDavid du Colombier 		dev = EARGF(usage());
7087dd7cddfSDavid du Colombier 		break;
7097dd7cddfSDavid du Colombier 	case 'm':
710e67f3b95SDavid du Colombier 		mtpt = EARGF(usage());
7117dd7cddfSDavid du Colombier 		break;
7127dd7cddfSDavid du Colombier 	case 'v':
7137dd7cddfSDavid du Colombier 		if((fd = create("/tmp/cdfs.log", OWRITE, 0666)) >= 0) {
7147dd7cddfSDavid du Colombier 			dup(fd, 2);
7157dd7cddfSDavid du Colombier 			dup(fd, 1);
7167dd7cddfSDavid du Colombier 			if(fd != 1 && fd != 2)
7177dd7cddfSDavid du Colombier 				close(fd);
7187dd7cddfSDavid du Colombier 			vflag++;
719436f307dSDavid du Colombier 			scsiverbose = 2; /* verbose but no Readtoc errs */
720*889a2622SDavid du Colombier 		} else
721*889a2622SDavid du Colombier 			fprint(2, "%s: can't open /tmp/cdfs.log: %r\n", argv0);
7227dd7cddfSDavid du Colombier 		break;
7237dd7cddfSDavid du Colombier 	default:
7247dd7cddfSDavid du Colombier 		usage();
7257dd7cddfSDavid du Colombier 	}ARGEND
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier 	if(dev == nil || mtpt == nil || argc > 0)
7287dd7cddfSDavid du Colombier 		usage();
7297dd7cddfSDavid du Colombier 
7302112d02cSDavid du Colombier 	werrstr("");
731c038c065SDavid du Colombier 	if((s = openscsi(dev)) == nil)
732c038c065SDavid du Colombier 		sysfatal("openscsi '%s': %r", dev);
733c038c065SDavid du Colombier 	if((drive = mmcprobe(s)) == nil)
734c038c065SDavid du Colombier 		sysfatal("mmcprobe '%s': %r", dev);
7357dd7cddfSDavid du Colombier 	checktoc(drive);
7367dd7cddfSDavid du Colombier 
7379a747e4fSDavid du Colombier 	postmountsrv(&fs, nil, mtpt, MREPL|MCREATE);
73880ee5cbfSDavid du Colombier 	exits(nil);
7397dd7cddfSDavid du Colombier }
740