xref: /plan9/sys/src/cmd/cdfs/main.c (revision 079e489f22cc31d0b95676a52cd6a83615606368)
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*
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*
4559cc4ca5SDavid du Colombier emalloc(ulong sz)
4659cc4ca5SDavid du Colombier {
4759cc4ca5SDavid du Colombier 	void *v;
4859cc4ca5SDavid du Colombier 
4959cc4ca5SDavid du Colombier 	v = malloc(sz);
5059cc4ca5SDavid du Colombier 	if(v == nil)
5159cc4ca5SDavid du Colombier 		sysfatal("malloc %lud fails\n", sz);
5259cc4ca5SDavid du Colombier 	memset(v, 0, sz);
5359cc4ca5SDavid du Colombier 	return v;
5459cc4ca5SDavid du Colombier }
5559cc4ca5SDavid du Colombier 
567dd7cddfSDavid du Colombier static void
579a747e4fSDavid du Colombier fsattach(Req *r)
587dd7cddfSDavid du Colombier {
599a747e4fSDavid du Colombier 	char *spec;
609a747e4fSDavid du Colombier 
619a747e4fSDavid du Colombier 	spec = r->ifcall.aname;
627dd7cddfSDavid du Colombier 	if(spec && spec[0]) {
637dd7cddfSDavid du Colombier 		respond(r, "invalid attach specifier");
647dd7cddfSDavid du Colombier 		return;
657dd7cddfSDavid du Colombier 	}
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier 	checktoc(drive);
689a747e4fSDavid du Colombier 	r->fid->qid = (Qid){Qdir, drive->nchange, QTDIR};
699a747e4fSDavid du Colombier 	r->ofcall.qid = r->fid->qid;
709a747e4fSDavid du Colombier 	r->fid->aux = emalloc(sizeof(Aux));
717dd7cddfSDavid du Colombier 	respond(r, nil);
727dd7cddfSDavid du Colombier }
737dd7cddfSDavid du Colombier 
749a747e4fSDavid du Colombier static char*
759a747e4fSDavid du Colombier fsclone(Fid *old, Fid *new)
767dd7cddfSDavid du Colombier {
779a747e4fSDavid du Colombier 	Aux *na;
787dd7cddfSDavid du Colombier 
799a747e4fSDavid du Colombier 	na = emalloc(sizeof(Aux));
809a747e4fSDavid du Colombier 	*na = *((Aux*)old->aux);
819a747e4fSDavid du Colombier 	if(na->o)
829a747e4fSDavid du Colombier 		na->o->nref++;
839a747e4fSDavid du Colombier 	new->aux = na;
849a747e4fSDavid du Colombier 	return nil;
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier 
879a747e4fSDavid du Colombier static char*
889a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
897dd7cddfSDavid du Colombier {
907dd7cddfSDavid du Colombier 	int i;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	checktoc(drive);
939a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path) {
947dd7cddfSDavid du Colombier 	case Qdir:
957dd7cddfSDavid du Colombier 		if(strcmp(name, "..") == 0) {
969a747e4fSDavid du Colombier 			*qid = (Qid){Qdir, drive->nchange, QTDIR};
979a747e4fSDavid du Colombier 			return nil;
987dd7cddfSDavid du Colombier 		}
997dd7cddfSDavid du Colombier 		if(strcmp(name, "ctl") == 0) {
1009a747e4fSDavid du Colombier 			*qid = (Qid){Qctl, 0, 0};
1019a747e4fSDavid du Colombier 			return nil;
1027dd7cddfSDavid du Colombier 		}
103436f307dSDavid du Colombier 		if(strcmp(name, "wa") == 0 && drive->writeok &&
104cdf9e71cSDavid du Colombier 		    (drive->mmctype == Mmcnone ||
105cdf9e71cSDavid du Colombier 		     drive->mmctype == Mmccd)) {
1069a747e4fSDavid du Colombier 			*qid = (Qid){Qwa, drive->nchange, QTDIR};
1079a747e4fSDavid du Colombier 			return nil;
1087dd7cddfSDavid du Colombier 		}
1097dd7cddfSDavid du Colombier 		if(strcmp(name, "wd") == 0 && drive->writeok) {
1109a747e4fSDavid du Colombier 			*qid = (Qid){Qwd, drive->nchange, QTDIR};
1119a747e4fSDavid du Colombier 			return nil;
1127dd7cddfSDavid du Colombier 		}
1137dd7cddfSDavid du Colombier 		for(i=0; i<drive->ntrack; i++)
1147dd7cddfSDavid du Colombier 			if(strcmp(drive->track[i].name, name) == 0)
1157dd7cddfSDavid du Colombier 				break;
1168ad6bb6aSDavid du Colombier 		if(i == drive->ntrack)
1179a747e4fSDavid du Colombier 			return "file not found";
1189a747e4fSDavid du Colombier 		*qid = (Qid){Qtrack+i, 0, 0};
1199a747e4fSDavid du Colombier 		return nil;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	case Qwa:
1227dd7cddfSDavid du Colombier 	case Qwd:
1237dd7cddfSDavid du Colombier 		if(strcmp(name, "..") == 0) {
1249a747e4fSDavid du Colombier 			*qid = (Qid){Qdir, drive->nchange, QTDIR};
1259a747e4fSDavid du Colombier 			return nil;
1267dd7cddfSDavid du Colombier 		}
1279a747e4fSDavid du Colombier 		return "file not found";
1287dd7cddfSDavid du Colombier 	default:	/* bug: lib9p could handle this */
1299a747e4fSDavid du Colombier 		return "walk in non-directory";
1307dd7cddfSDavid du Colombier 	}
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier static void
1349a747e4fSDavid du Colombier fscreate(Req *r)
1357dd7cddfSDavid du Colombier {
1369a747e4fSDavid du Colombier 	int omode, type;
1377dd7cddfSDavid du Colombier 	Otrack *o;
1389a747e4fSDavid du Colombier 	Fid *fid;
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier 	fid = r->fid;
1419a747e4fSDavid du Colombier 	omode = r->ifcall.mode;
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	if(omode != OWRITE) {
1447dd7cddfSDavid du Colombier 		respond(r, "bad mode (use OWRITE)");
1457dd7cddfSDavid du Colombier 		return;
1467dd7cddfSDavid du Colombier 	}
1477dd7cddfSDavid du Colombier 
1489a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path) {
1497dd7cddfSDavid du Colombier 	case Qdir:
1507dd7cddfSDavid du Colombier 	default:
1517dd7cddfSDavid du Colombier 		respond(r, "permission denied");
1527dd7cddfSDavid du Colombier 		return;
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	case Qwa:
155cdf9e71cSDavid du Colombier 		if (drive->mmctype != Mmcnone &&
156cdf9e71cSDavid du Colombier 		    drive->mmctype != Mmccd) {
157436f307dSDavid du Colombier 			respond(r, "audio supported only on cd");
158436f307dSDavid du Colombier 			return;
159436f307dSDavid du Colombier 		}
1607dd7cddfSDavid du Colombier 		type = TypeAudio;
1617dd7cddfSDavid du Colombier 		break;
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	case Qwd:
1647dd7cddfSDavid du Colombier 		type = TypeData;
1657dd7cddfSDavid du Colombier 		break;
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier 	if((drive->cap & Cwrite) == 0) {
1697dd7cddfSDavid du Colombier 		respond(r, "drive does not write");
1707dd7cddfSDavid du Colombier 		return;
1717dd7cddfSDavid du Colombier 	}
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	o = drive->create(drive, type);
1747dd7cddfSDavid du Colombier 	if(o == nil) {
1757dd7cddfSDavid du Colombier 		respond(r, geterrstr());
1767dd7cddfSDavid du Colombier 		return;
1777dd7cddfSDavid du Colombier 	}
1787dd7cddfSDavid du Colombier 	drive->nchange = -1;
1797dd7cddfSDavid du Colombier 	checktoc(drive);	/* update directory info */
1807dd7cddfSDavid du Colombier 	o->nref = 1;
1819a747e4fSDavid du Colombier 	((Aux*)fid->aux)->o = o;
1827dd7cddfSDavid du Colombier 
1839a747e4fSDavid du Colombier 	fid->qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange, 0};
1849a747e4fSDavid du Colombier 	r->ofcall.qid = fid->qid;
1857dd7cddfSDavid du Colombier 	respond(r, nil);
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier static void
1899a747e4fSDavid du Colombier fsremove(Req *r)
1907dd7cddfSDavid du Colombier {
1919a747e4fSDavid du Colombier 	switch((ulong)r->fid->qid.path){
1927dd7cddfSDavid du Colombier 	case Qwa:
1937dd7cddfSDavid du Colombier 	case Qwd:
1947dd7cddfSDavid du Colombier 		if(drive->fixate(drive) < 0)
1957dd7cddfSDavid du Colombier 			respond(r, geterrstr());
1967dd7cddfSDavid du Colombier // let's see if it can figure this out		drive->writeok = 0;
1977dd7cddfSDavid du Colombier 		else
1987dd7cddfSDavid du Colombier 			respond(r, nil);
1997dd7cddfSDavid du Colombier 		checktoc(drive);
2007dd7cddfSDavid du Colombier 		break;
2017dd7cddfSDavid du Colombier 	default:
2027dd7cddfSDavid du Colombier 		respond(r, "permission denied");
2037dd7cddfSDavid du Colombier 		break;
2047dd7cddfSDavid du Colombier 	}
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
207*079e489fSDavid du Colombier static char *
208*079e489fSDavid du Colombier disctype(Drive *drive)
209*079e489fSDavid du Colombier {
210*079e489fSDavid du Colombier 	char *type, *rw;
211*079e489fSDavid du Colombier 
212*079e489fSDavid du Colombier 	switch (drive->mmctype) {
213*079e489fSDavid du Colombier 	case Mmccd:
214*079e489fSDavid du Colombier 		type = "cd-";
215*079e489fSDavid du Colombier 		break;
216*079e489fSDavid du Colombier 	case Mmcdvdminus:
217*079e489fSDavid du Colombier 	case Mmcdvdplus:
218*079e489fSDavid du Colombier 		type = drive->dvdtype;
219*079e489fSDavid du Colombier 		break;
220*079e489fSDavid du Colombier 	case Mmcbd:
221*079e489fSDavid du Colombier 		type = "bd-";
222*079e489fSDavid du Colombier 		break;
223*079e489fSDavid du Colombier 	case Mmcnone:
224*079e489fSDavid du Colombier 		type = "no disc";
225*079e489fSDavid du Colombier 		break;
226*079e489fSDavid du Colombier 	default:
227*079e489fSDavid du Colombier 		type = "**GOK**";		/* traditional */
228*079e489fSDavid du Colombier 		break;
229*079e489fSDavid du Colombier 	}
230*079e489fSDavid du Colombier 	rw = "";
231*079e489fSDavid du Colombier 	if (drive->mmctype != Mmcnone && drive->dvdtype == nil)
232*079e489fSDavid du Colombier 		if (drive->erasable)
233*079e489fSDavid du Colombier 			rw = "rw";
234*079e489fSDavid du Colombier 		else if (drive->recordable)
235*079e489fSDavid du Colombier 			rw = "r";
236*079e489fSDavid du Colombier 		else
237*079e489fSDavid du Colombier 			rw = "rom";
238*079e489fSDavid du Colombier 	return smprint("%s%s", type, rw);
239*079e489fSDavid du Colombier }
240*079e489fSDavid du Colombier 
2417dd7cddfSDavid du Colombier int
2429a747e4fSDavid du Colombier fillstat(ulong qid, Dir *d)
2437dd7cddfSDavid du Colombier {
244*079e489fSDavid du Colombier 	char *ty;
2457dd7cddfSDavid du Colombier 	Track *t;
246*079e489fSDavid du Colombier 	static char buf[32];
2477dd7cddfSDavid du Colombier 
248e67f3b95SDavid du Colombier 	nulldir(d);
249e67f3b95SDavid du Colombier 	d->type = L'M';
250e67f3b95SDavid du Colombier 	d->dev = 1;
251e67f3b95SDavid du Colombier 	d->length = 0;
252*079e489fSDavid du Colombier 	ty = disctype(drive);
253*079e489fSDavid du Colombier 	strncpy(buf, ty, sizeof buf);
254*079e489fSDavid du Colombier 	free(ty);
255*079e489fSDavid du Colombier 	d->uid = d->gid = buf;
2569a747e4fSDavid du Colombier 	d->muid = "";
2579a747e4fSDavid du Colombier 	d->qid = (Qid){qid, drive->nchange, 0};
2587dd7cddfSDavid du Colombier 	d->atime = time(0);
259e67f3b95SDavid du Colombier 	d->mtime = drive->changetime;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	switch(qid){
2627dd7cddfSDavid du Colombier 	case Qdir:
2639a747e4fSDavid du Colombier 		d->name = "/";
2649a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2659a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
2667dd7cddfSDavid du Colombier 		break;
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	case Qctl:
2699a747e4fSDavid du Colombier 		d->name = "ctl";
2707dd7cddfSDavid du Colombier 		d->mode = 0666;
2717dd7cddfSDavid du Colombier 		break;
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	case Qwa:
274436f307dSDavid du Colombier 		if(drive->writeok == 0 ||
275cdf9e71cSDavid du Colombier 		    drive->mmctype != Mmcnone &&
276cdf9e71cSDavid du Colombier 		    drive->mmctype != Mmccd)
2777dd7cddfSDavid du Colombier 			return 0;
2789a747e4fSDavid du Colombier 		d->name = "wa";
2799a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2809a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
2817dd7cddfSDavid du Colombier 		break;
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier 	case Qwd:
2847dd7cddfSDavid du Colombier 		if(drive->writeok == 0)
2857dd7cddfSDavid du Colombier 			return 0;
2869a747e4fSDavid du Colombier 		d->name = "wd";
2879a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2889a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
2897dd7cddfSDavid du Colombier 		break;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier 	default:
2927dd7cddfSDavid du Colombier 		if(qid-Qtrack >= drive->ntrack)
2937dd7cddfSDavid du Colombier 			return 0;
2947dd7cddfSDavid du Colombier 		t = &drive->track[qid-Qtrack];
2957dd7cddfSDavid du Colombier 		if(strcmp(t->name, "") == 0)
2967dd7cddfSDavid du Colombier 			return 0;
2979a747e4fSDavid du Colombier 		d->name = t->name;
2987dd7cddfSDavid du Colombier 		d->mode = t->mode;
2997dd7cddfSDavid du Colombier 		d->length = t->size;
3007dd7cddfSDavid du Colombier 		break;
3017dd7cddfSDavid du Colombier 	}
3027dd7cddfSDavid du Colombier 	return 1;
3037dd7cddfSDavid du Colombier }
3047dd7cddfSDavid du Colombier 
3059a747e4fSDavid du Colombier static ulong
3069a747e4fSDavid du Colombier cddb_sum(int n)
3077dd7cddfSDavid du Colombier {
3089a747e4fSDavid du Colombier 	int ret;
3099a747e4fSDavid du Colombier 	ret = 0;
3109a747e4fSDavid du Colombier 	while(n > 0) {
3119a747e4fSDavid du Colombier 		ret += n%10;
3129a747e4fSDavid du Colombier 		n /= 10;
3139a747e4fSDavid du Colombier 	}
3149a747e4fSDavid du Colombier 	return ret;
3159a747e4fSDavid du Colombier }
3169a747e4fSDavid du Colombier 
3179a747e4fSDavid du Colombier static ulong
3189a747e4fSDavid du Colombier diskid(Drive *d)
3199a747e4fSDavid du Colombier {
3209a747e4fSDavid du Colombier 	int i, n;
3219a747e4fSDavid du Colombier 	ulong tmp;
3229a747e4fSDavid du Colombier 	Msf *ms, *me;
3239a747e4fSDavid du Colombier 
3249a747e4fSDavid du Colombier 	n = 0;
3259a747e4fSDavid du Colombier 	for(i=0; i < d->ntrack; i++)
3269a747e4fSDavid du Colombier 		n += cddb_sum(d->track[i].mbeg.m*60+d->track[i].mbeg.s);
3279a747e4fSDavid du Colombier 
3289a747e4fSDavid du Colombier 	ms = &d->track[0].mbeg;
3299a747e4fSDavid du Colombier 	me = &d->track[d->ntrack].mbeg;
3309a747e4fSDavid du Colombier 	tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
3319a747e4fSDavid du Colombier 
3329a747e4fSDavid du Colombier 	/*
3338ad6bb6aSDavid du Colombier 	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is
3348ad6bb6aSDavid du Colombier 	 * correct.  most CDs are in the database under both entries.
3359a747e4fSDavid du Colombier 	 */
3369a747e4fSDavid du Colombier 	return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier static void
3409a747e4fSDavid du Colombier readctl(Req *r)
3417dd7cddfSDavid du Colombier {
3429a747e4fSDavid du Colombier 	int i, isaudio;
343*079e489fSDavid du Colombier 	char *p, *e, *ty;
3449a747e4fSDavid du Colombier 	char s[1024];
3459a747e4fSDavid du Colombier 	Msf *m;
3467dd7cddfSDavid du Colombier 
3479a747e4fSDavid du Colombier 	isaudio = 0;
3489a747e4fSDavid du Colombier 	for(i=0; i<drive->ntrack; i++)
3499a747e4fSDavid du Colombier 		if(drive->track[i].type == TypeAudio)
3509a747e4fSDavid du Colombier 			isaudio = 1;
3519a747e4fSDavid du Colombier 
3528ad6bb6aSDavid du Colombier 	p = s;
3538ad6bb6aSDavid du Colombier 	e = s + sizeof s;
3548ad6bb6aSDavid du Colombier 	*p = '\0';
3559a747e4fSDavid du Colombier 	if(isaudio){
3568ad6bb6aSDavid du Colombier 		p = seprint(p, e, "aux/cddb query %8.8lux %d", diskid(drive),
3578ad6bb6aSDavid du Colombier 			drive->ntrack);
3589a747e4fSDavid du Colombier 		for(i=0; i<drive->ntrack; i++){
3599a747e4fSDavid du Colombier 			m = &drive->track[i].mbeg;
3608ad6bb6aSDavid du Colombier 			p = seprint(p, e, " %d", (m->m*60 + m->s)*75 + m->f);
3619a747e4fSDavid du Colombier 		}
3629a747e4fSDavid du Colombier 		m = &drive->track[drive->ntrack].mbeg;
3638ad6bb6aSDavid du Colombier 		p = seprint(p, e, " %d\n", m->m*60 + m->s);
3649a747e4fSDavid du Colombier 	}
3659a747e4fSDavid du Colombier 
3669a747e4fSDavid du Colombier 	if(drive->readspeed == drive->writespeed)
3678ad6bb6aSDavid du Colombier 		p = seprint(p, e, "speed %d\n", drive->readspeed);
3689a747e4fSDavid du Colombier 	else
3698ad6bb6aSDavid du Colombier 		p = seprint(p, e, "speed read %d write %d\n",
370cdf9e71cSDavid du Colombier 			drive->readspeed, drive->writespeed);
3718ad6bb6aSDavid du Colombier 	p = seprint(p, e, "maxspeed read %d write %d\n",
372cdf9e71cSDavid du Colombier 		drive->maxreadspeed, drive->maxwritespeed);
3738ad6bb6aSDavid du Colombier 
3748ad6bb6aSDavid du Colombier 	if (drive->Scsi.changetime != 0 && drive->ntrack != 0) { /* have disc? */
375*079e489fSDavid du Colombier 		ty = disctype(drive);
376*079e489fSDavid du Colombier 		p = seprint(p, e, "%s", ty);
377*079e489fSDavid du Colombier 		free(ty);
378*079e489fSDavid du Colombier 		if (drive->mmctype != Mmcnone)
3798ad6bb6aSDavid du Colombier 			p = seprint(p, e, " next writable sector %lud",
3808ad6bb6aSDavid du Colombier 				getnwa(drive));
3818ad6bb6aSDavid du Colombier 		seprint(p, e, "\n");
3828ad6bb6aSDavid du Colombier 	}
3839a747e4fSDavid du Colombier 	readstr(r, s);
3849a747e4fSDavid du Colombier }
3859a747e4fSDavid du Colombier 
3869a747e4fSDavid du Colombier static void
3879a747e4fSDavid du Colombier fsread(Req *r)
3889a747e4fSDavid du Colombier {
3899a747e4fSDavid du Colombier 	int j, n, m;
3909a747e4fSDavid du Colombier 	uchar *p, *ep;
3919a747e4fSDavid du Colombier 	Dir d;
3929a747e4fSDavid du Colombier 	Fid *fid;
3939a747e4fSDavid du Colombier 	Otrack *o;
3949a747e4fSDavid du Colombier 	vlong offset;
3959a747e4fSDavid du Colombier 	void *buf;
3969a747e4fSDavid du Colombier 	long count;
3979a747e4fSDavid du Colombier 	Aux *a;
3989a747e4fSDavid du Colombier 
3999a747e4fSDavid du Colombier 	fid = r->fid;
4009a747e4fSDavid du Colombier 	offset = r->ifcall.offset;
4019a747e4fSDavid du Colombier 	buf = r->ofcall.data;
4029a747e4fSDavid du Colombier 	count = r->ifcall.count;
4039a747e4fSDavid du Colombier 
4049a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path) {
4057dd7cddfSDavid du Colombier 	case Qdir:
4067dd7cddfSDavid du Colombier 		checktoc(drive);
4077dd7cddfSDavid du Colombier 		p = buf;
4089a747e4fSDavid du Colombier 		ep = p+count;
4097dd7cddfSDavid du Colombier 		m = Qtrack+drive->ntrack;
4109a747e4fSDavid du Colombier 		a = fid->aux;
4119a747e4fSDavid du Colombier 		if(offset == 0)
4129a747e4fSDavid du Colombier 			a->doff = 1;	/* skip root */
4139a747e4fSDavid du Colombier 
4149a747e4fSDavid du Colombier 		for(j=a->doff; j<m; j++) {
4157dd7cddfSDavid du Colombier 			if(fillstat(j, &d)) {
4169a747e4fSDavid du Colombier 				if((n = convD2M(&d, p, ep-p)) <= BIT16SZ)
4179a747e4fSDavid du Colombier 					break;
4189a747e4fSDavid du Colombier 				p += n;
4197dd7cddfSDavid du Colombier 			}
4207dd7cddfSDavid du Colombier 		}
4219a747e4fSDavid du Colombier 		a->doff = j;
4229a747e4fSDavid du Colombier 
4239a747e4fSDavid du Colombier 		r->ofcall.count = p - (uchar*)buf;
424cdf9e71cSDavid du Colombier 		break;
4257dd7cddfSDavid du Colombier 	case Qwa:
4267dd7cddfSDavid du Colombier 	case Qwd:
4279a747e4fSDavid du Colombier 		r->ofcall.count = 0;
428cdf9e71cSDavid du Colombier 		break;
4297dd7cddfSDavid du Colombier 	case Qctl:
4309a747e4fSDavid du Colombier 		readctl(r);
431cdf9e71cSDavid du Colombier 		break;
432cdf9e71cSDavid du Colombier 	default:
4337dd7cddfSDavid du Colombier 		/* a disk track; we can only call read for whole blocks */
4349a747e4fSDavid du Colombier 		o = ((Aux*)fid->aux)->o;
435cdf9e71cSDavid du Colombier 		if((count = o->drive->read(o, buf, count, offset)) < 0) {
4367dd7cddfSDavid du Colombier 			respond(r, geterrstr());
437cdf9e71cSDavid du Colombier 			return;
4389a747e4fSDavid du Colombier 		}
439cdf9e71cSDavid du Colombier 		r->ofcall.count = count;
440cdf9e71cSDavid du Colombier 		break;
441cdf9e71cSDavid du Colombier 	}
442cdf9e71cSDavid du Colombier 	respond(r, nil);
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier 
4459a747e4fSDavid du Colombier static char *Ebadmsg = "bad cdfs control message";
446c038c065SDavid du Colombier 
4477dd7cddfSDavid du Colombier static char*
4487dd7cddfSDavid du Colombier writectl(void *v, long count)
4497dd7cddfSDavid du Colombier {
4507dd7cddfSDavid du Colombier 	char buf[256];
4519a747e4fSDavid du Colombier 	char *f[10], *p;
4529a747e4fSDavid du Colombier 	int i, nf, n, r, w, what;
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier 	if(count >= sizeof(buf))
4557dd7cddfSDavid du Colombier 		count = sizeof(buf)-1;
4567dd7cddfSDavid du Colombier 	memmove(buf, v, count);
4577dd7cddfSDavid du Colombier 	buf[count] = '\0';
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	nf = tokenize(buf, f, nelem(f));
4609a747e4fSDavid du Colombier 	if(nf == 0)
4619a747e4fSDavid du Colombier 		return Ebadmsg;
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier 	if(strcmp(f[0], "speed") == 0){
4649a747e4fSDavid du Colombier 		what = 0;
4659a747e4fSDavid du Colombier 		r = w = -1;
4669a747e4fSDavid du Colombier 		if(nf == 1)
4679a747e4fSDavid du Colombier 			return Ebadmsg;
4689a747e4fSDavid du Colombier 		for(i=1; i<nf; i++){
4699a747e4fSDavid du Colombier 			if(strcmp(f[i], "read") == 0 || strcmp(f[i], "write") == 0){
4709a747e4fSDavid du Colombier 				if(what!=0 && what!='?')
4719a747e4fSDavid du Colombier 					return Ebadmsg;
4729a747e4fSDavid du Colombier 				what = f[i][0];
4739a747e4fSDavid du Colombier 			}else{
4749a747e4fSDavid du Colombier 				n = strtol(f[i], &p, 0);
4759a747e4fSDavid du Colombier 				if(*p != '\0' || n <= 0)
4769a747e4fSDavid du Colombier 					return Ebadmsg;
4779a747e4fSDavid du Colombier 				switch(what){
4789a747e4fSDavid du Colombier 				case 0:
4799a747e4fSDavid du Colombier 					if(r >= 0 || w >= 0)
4809a747e4fSDavid du Colombier 						return Ebadmsg;
4819a747e4fSDavid du Colombier 					r = w = n;
4829a747e4fSDavid du Colombier 					break;
4839a747e4fSDavid du Colombier 				case 'r':
4849a747e4fSDavid du Colombier 					if(r >= 0)
4859a747e4fSDavid du Colombier 						return Ebadmsg;
4869a747e4fSDavid du Colombier 					r = n;
4879a747e4fSDavid du Colombier 					break;
4889a747e4fSDavid du Colombier 				case 'w':
4899a747e4fSDavid du Colombier 					if(w >= 0)
4909a747e4fSDavid du Colombier 						return Ebadmsg;
4919a747e4fSDavid du Colombier 					w = n;
4929a747e4fSDavid du Colombier 					break;
4939a747e4fSDavid du Colombier 				default:
4949a747e4fSDavid du Colombier 					return Ebadmsg;
4959a747e4fSDavid du Colombier 				}
496cdf9e71cSDavid du Colombier 				what = '?';
4979a747e4fSDavid du Colombier 			}
4989a747e4fSDavid du Colombier 		}
4999a747e4fSDavid du Colombier 		if(what != '?')
5009a747e4fSDavid du Colombier 			return Ebadmsg;
5019a747e4fSDavid du Colombier 		return drive->setspeed(drive, r, w);
5029a747e4fSDavid du Colombier 	}
5037dd7cddfSDavid du Colombier 	return drive->ctl(drive, nf, f);
5047dd7cddfSDavid du Colombier }
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier static void
5079a747e4fSDavid du Colombier fswrite(Req *r)
5087dd7cddfSDavid du Colombier {
5097dd7cddfSDavid du Colombier 	Otrack *o;
5109a747e4fSDavid du Colombier 	Fid *fid;
5117dd7cddfSDavid du Colombier 
5129a747e4fSDavid du Colombier 	fid = r->fid;
5139a747e4fSDavid du Colombier 	r->ofcall.count = r->ifcall.count;
5147dd7cddfSDavid du Colombier 	if(fid->qid.path == Qctl) {
5159a747e4fSDavid du Colombier 		respond(r, writectl(r->ifcall.data, r->ifcall.count));
5167dd7cddfSDavid du Colombier 		return;
5177dd7cddfSDavid du Colombier 	}
5187dd7cddfSDavid du Colombier 
5199a747e4fSDavid du Colombier 	if((o = ((Aux*)fid->aux)->o) == nil || o->omode != OWRITE) {
5207dd7cddfSDavid du Colombier 		respond(r, "permission denied");
5217dd7cddfSDavid du Colombier 		return;
5227dd7cddfSDavid du Colombier 	}
5237dd7cddfSDavid du Colombier 
5249a747e4fSDavid du Colombier 	if(o->drive->write(o, r->ifcall.data, r->ifcall.count) < 0)
5257dd7cddfSDavid du Colombier 		respond(r, geterrstr());
5267dd7cddfSDavid du Colombier 	else
5277dd7cddfSDavid du Colombier 		respond(r, nil);
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier 
5307dd7cddfSDavid du Colombier static void
5319a747e4fSDavid du Colombier fsstat(Req *r)
5327dd7cddfSDavid du Colombier {
5339a747e4fSDavid du Colombier 	fillstat((ulong)r->fid->qid.path, &r->d);
5349a747e4fSDavid du Colombier 	r->d.name = estrdup9p(r->d.name);
5359a747e4fSDavid du Colombier 	r->d.uid = estrdup9p(r->d.uid);
5369a747e4fSDavid du Colombier 	r->d.gid = estrdup9p(r->d.gid);
5379a747e4fSDavid du Colombier 	r->d.muid = estrdup9p(r->d.muid);
5387dd7cddfSDavid du Colombier 	respond(r, nil);
5397dd7cddfSDavid du Colombier }
5407dd7cddfSDavid du Colombier 
5417dd7cddfSDavid du Colombier static void
5429a747e4fSDavid du Colombier fsopen(Req *r)
5437dd7cddfSDavid du Colombier {
5449a747e4fSDavid du Colombier 	int omode;
5459a747e4fSDavid du Colombier 	Fid *fid;
5467dd7cddfSDavid du Colombier 	Otrack *o;
5477dd7cddfSDavid du Colombier 
5489a747e4fSDavid du Colombier 	fid = r->fid;
5499a747e4fSDavid du Colombier 	omode = r->ifcall.mode;
5507dd7cddfSDavid du Colombier 	checktoc(drive);
5519a747e4fSDavid du Colombier 	r->ofcall.qid = (Qid){fid->qid.path, drive->nchange, fid->qid.vers};
5527dd7cddfSDavid du Colombier 
5539a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path){
5547dd7cddfSDavid du Colombier 	case Qdir:
5557dd7cddfSDavid du Colombier 	case Qwa:
5567dd7cddfSDavid du Colombier 	case Qwd:
557cdf9e71cSDavid du Colombier 		if(omode != OREAD) {
5587dd7cddfSDavid du Colombier 			respond(r, "permission denied");
5597dd7cddfSDavid du Colombier 			return;
560cdf9e71cSDavid du Colombier 		}
561cdf9e71cSDavid du Colombier 		break;
5627dd7cddfSDavid du Colombier 	case Qctl:
563cdf9e71cSDavid du Colombier 		if(omode & ~(OTRUNC|OREAD|OWRITE|ORDWR)) {
5647dd7cddfSDavid du Colombier 			respond(r, "permission denied");
5657dd7cddfSDavid du Colombier 			return;
566cdf9e71cSDavid du Colombier 		}
567cdf9e71cSDavid du Colombier 		break;
5687dd7cddfSDavid du Colombier 	default:
5697dd7cddfSDavid du Colombier 		if(fid->qid.path >= Qtrack+drive->ntrack) {
5707dd7cddfSDavid du Colombier 			respond(r, "file no longer exists");
5717dd7cddfSDavid du Colombier 			return;
5727dd7cddfSDavid du Colombier 		}
5737dd7cddfSDavid du Colombier 
574c038c065SDavid du Colombier 		/*
575c038c065SDavid du Colombier 		 * allow the open with OWRITE or ORDWR if the
576c038c065SDavid du Colombier 		 * drive and disc are both capable?
577c038c065SDavid du Colombier 		 */
578c038c065SDavid du Colombier 		if(omode != OREAD ||
579c038c065SDavid du Colombier 		    (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
5807dd7cddfSDavid du Colombier 			respond(r, "permission denied");
5817dd7cddfSDavid du Colombier 			return;
5827dd7cddfSDavid du Colombier 		}
5837dd7cddfSDavid du Colombier 
5847dd7cddfSDavid du Colombier 		o->nref = 1;
5859a747e4fSDavid du Colombier 		((Aux*)fid->aux)->o = o;
586c038c065SDavid du Colombier 		break;
5877dd7cddfSDavid du Colombier 	}
588cdf9e71cSDavid du Colombier 	respond(r, nil);
5897dd7cddfSDavid du Colombier }
5907dd7cddfSDavid du Colombier 
5917dd7cddfSDavid du Colombier static void
5929a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
5937dd7cddfSDavid du Colombier {
5949a747e4fSDavid du Colombier 	Aux *aux;
5957dd7cddfSDavid du Colombier 	Otrack *o;
5967dd7cddfSDavid du Colombier 
5979a747e4fSDavid du Colombier 	aux = fid->aux;
5989a747e4fSDavid du Colombier 	if(aux == nil)
5999a747e4fSDavid du Colombier 		return;
6009a747e4fSDavid du Colombier 	o = aux->o;
6017dd7cddfSDavid du Colombier 	if(o && --o->nref == 0) {
6027dd7cddfSDavid du Colombier 		bterm(o->buf);
6037dd7cddfSDavid du Colombier 		drive->close(o);
6047dd7cddfSDavid du Colombier 		checktoc(drive);
6057dd7cddfSDavid du Colombier 	}
6067dd7cddfSDavid du Colombier }
6077dd7cddfSDavid du Colombier 
6087dd7cddfSDavid du Colombier static void
6097dd7cddfSDavid du Colombier checktoc(Drive *drive)
6107dd7cddfSDavid du Colombier {
6117dd7cddfSDavid du Colombier 	int i;
6127dd7cddfSDavid du Colombier 	Track *t;
6137dd7cddfSDavid du Colombier 
6147dd7cddfSDavid du Colombier 	drive->gettoc(drive);
6157dd7cddfSDavid du Colombier 	if(drive->nameok)
6167dd7cddfSDavid du Colombier 		return;
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier 	for(i=0; i<drive->ntrack; i++) {
6197dd7cddfSDavid du Colombier 		t = &drive->track[i];
6207dd7cddfSDavid du Colombier 		if(t->size == 0)	/* being created */
6217dd7cddfSDavid du Colombier 			t->mode = 0;
6227dd7cddfSDavid du Colombier 		else
6237dd7cddfSDavid du Colombier 			t->mode = 0444;
6247dd7cddfSDavid du Colombier 		sprint(t->name, "?%.3d", i);
6257dd7cddfSDavid du Colombier 		switch(t->type){
6267dd7cddfSDavid du Colombier 		case TypeNone:
6277dd7cddfSDavid du Colombier 			t->name[0] = 'u';
628e67f3b95SDavid du Colombier //			t->mode = 0;
6297dd7cddfSDavid du Colombier 			break;
6307dd7cddfSDavid du Colombier 		case TypeData:
6317dd7cddfSDavid du Colombier 			t->name[0] = 'd';
6327dd7cddfSDavid du Colombier 			break;
6337dd7cddfSDavid du Colombier 		case TypeAudio:
6347dd7cddfSDavid du Colombier 			t->name[0] = 'a';
6357dd7cddfSDavid du Colombier 			break;
6367dd7cddfSDavid du Colombier 		case TypeBlank:
6377dd7cddfSDavid du Colombier 			t->name[0] = '\0';
6387dd7cddfSDavid du Colombier 			break;
6397dd7cddfSDavid du Colombier 		default:
640*079e489fSDavid du Colombier 			print("unknown track type %d\n", t->type);
6417dd7cddfSDavid du Colombier 			break;
6427dd7cddfSDavid du Colombier 		}
6437dd7cddfSDavid du Colombier 	}
6447dd7cddfSDavid du Colombier 
6457dd7cddfSDavid du Colombier 	drive->nameok = 1;
6467dd7cddfSDavid du Colombier }
6477dd7cddfSDavid du Colombier 
6487dd7cddfSDavid du Colombier long
6497dd7cddfSDavid du Colombier bufread(Otrack *t, void *v, long n, long off)
6507dd7cddfSDavid du Colombier {
6517dd7cddfSDavid du Colombier 	return bread(t->buf, v, n, off);
6527dd7cddfSDavid du Colombier }
6537dd7cddfSDavid du Colombier 
6547dd7cddfSDavid du Colombier long
6557dd7cddfSDavid du Colombier bufwrite(Otrack *t, void *v, long n)
6567dd7cddfSDavid du Colombier {
6577dd7cddfSDavid du Colombier 	return bwrite(t->buf, v, n);
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier 
6609a747e4fSDavid du Colombier Srv fs = {
6619a747e4fSDavid du Colombier .attach=	fsattach,
6629a747e4fSDavid du Colombier .destroyfid=	fsdestroyfid,
6639a747e4fSDavid du Colombier .clone=		fsclone,
6649a747e4fSDavid du Colombier .walk1=		fswalk1,
6659a747e4fSDavid du Colombier .open=		fsopen,
6669a747e4fSDavid du Colombier .read=		fsread,
6679a747e4fSDavid du Colombier .write=		fswrite,
6689a747e4fSDavid du Colombier .create=	fscreate,
6699a747e4fSDavid du Colombier .remove=	fsremove,
6709a747e4fSDavid du Colombier .stat=		fsstat,
6717dd7cddfSDavid du Colombier };
6727dd7cddfSDavid du Colombier 
6737dd7cddfSDavid du Colombier void
6747dd7cddfSDavid du Colombier usage(void)
6757dd7cddfSDavid du Colombier {
6769a747e4fSDavid du Colombier 	fprint(2, "usage: cdfs [-Dv] [-d /dev/sdC0] [-m mtpt]\n");
6777dd7cddfSDavid du Colombier 	exits("usage");
6787dd7cddfSDavid du Colombier }
6797dd7cddfSDavid du Colombier 
6807dd7cddfSDavid du Colombier void
6817dd7cddfSDavid du Colombier main(int argc, char **argv)
6827dd7cddfSDavid du Colombier {
6837dd7cddfSDavid du Colombier 	Scsi *s;
6847dd7cddfSDavid du Colombier 	int fd;
6857dd7cddfSDavid du Colombier 	char *dev, *mtpt;
6867dd7cddfSDavid du Colombier 
6877dd7cddfSDavid du Colombier 	dev = "/dev/sdD0";
6887dd7cddfSDavid du Colombier 	mtpt = "/mnt/cd";
6897dd7cddfSDavid du Colombier 
6907dd7cddfSDavid du Colombier 	ARGBEGIN{
6919a747e4fSDavid du Colombier 	case 'D':
6929a747e4fSDavid du Colombier 		chatty9p++;
6939a747e4fSDavid du Colombier 		break;
6947dd7cddfSDavid du Colombier 	case 'd':
695e67f3b95SDavid du Colombier 		dev = EARGF(usage());
6967dd7cddfSDavid du Colombier 		break;
6977dd7cddfSDavid du Colombier 	case 'm':
698e67f3b95SDavid du Colombier 		mtpt = EARGF(usage());
6997dd7cddfSDavid du Colombier 		break;
7007dd7cddfSDavid du Colombier 	case 'v':
7017dd7cddfSDavid du Colombier 		if((fd = create("/tmp/cdfs.log", OWRITE, 0666)) >= 0) {
7027dd7cddfSDavid du Colombier 			dup(fd, 2);
7037dd7cddfSDavid du Colombier 			dup(fd, 1);
7047dd7cddfSDavid du Colombier 			if(fd != 1 && fd != 2)
7057dd7cddfSDavid du Colombier 				close(fd);
7067dd7cddfSDavid du Colombier 			vflag++;
707436f307dSDavid du Colombier 			scsiverbose = 2; /* verbose but no Readtoc errs */
7087dd7cddfSDavid du Colombier 		}
7097dd7cddfSDavid du Colombier 		break;
7107dd7cddfSDavid du Colombier 	default:
7117dd7cddfSDavid du Colombier 		usage();
7127dd7cddfSDavid du Colombier 	}ARGEND
7137dd7cddfSDavid du Colombier 
7147dd7cddfSDavid du Colombier 	if(dev == nil || mtpt == nil || argc > 0)
7157dd7cddfSDavid du Colombier 		usage();
7167dd7cddfSDavid du Colombier 
717c038c065SDavid du Colombier 	if((s = openscsi(dev)) == nil)
718c038c065SDavid du Colombier 		sysfatal("openscsi '%s': %r", dev);
719c038c065SDavid du Colombier 	if((drive = mmcprobe(s)) == nil)
720c038c065SDavid du Colombier 		sysfatal("mmcprobe '%s': %r", dev);
7217dd7cddfSDavid du Colombier 	checktoc(drive);
7227dd7cddfSDavid du Colombier 
7239a747e4fSDavid du Colombier 	postmountsrv(&fs, nil, mtpt, MREPL|MCREATE);
72480ee5cbfSDavid du Colombier 	exits(nil);
7257dd7cddfSDavid du Colombier }
726