Browse Source

Plan 9 from Bell Labs 2008-03-21

David du Colombier 16 years ago
parent
commit
1f23768a8d

+ 8 - 10
dist/replica/_plan9.db

@@ -172,7 +172,7 @@
 386/bin/calendar - 775 sys sys 1200262736 79060
 386/bin/calendar - 775 sys sys 1200262736 79060
 386/bin/cat - 775 sys sys 1148500611 37482
 386/bin/cat - 775 sys sys 1148500611 37482
 386/bin/cb - 775 sys sys 1168402293 77628
 386/bin/cb - 775 sys sys 1168402293 77628
-386/bin/cdfs - 775 sys sys 1205524026 171999
+386/bin/cdfs - 775 sys sys 1206069507 173352
 386/bin/cec - 775 sys sys 1193714267 75896
 386/bin/cec - 775 sys sys 1193714267 75896
 386/bin/cfs - 775 sys sys 1190863294 130565
 386/bin/cfs - 775 sys sys 1190863294 130565
 386/bin/chgrp - 775 sys sys 1168402294 59522
 386/bin/chgrp - 775 sys sys 1168402294 59522
@@ -353,7 +353,7 @@
 386/bin/ndb/mkdb - 775 sys sys 1168402340 64211
 386/bin/ndb/mkdb - 775 sys sys 1168402340 64211
 386/bin/ndb/mkhash - 775 sys sys 1178568296 83312
 386/bin/ndb/mkhash - 775 sys sys 1178568296 83312
 386/bin/ndb/mkhosts - 775 sys sys 1178568296 84355
 386/bin/ndb/mkhosts - 775 sys sys 1178568296 84355
-386/bin/ndb/query - 775 sys sys 1188447268 82960
+386/bin/ndb/query - 775 sys sys 1206042296 83761
 386/bin/netkey - 775 sys sys 1168402341 72717
 386/bin/netkey - 775 sys sys 1168402341 72717
 386/bin/netstat - 775 sys sys 1204292542 86477
 386/bin/netstat - 775 sys sys 1204292542 86477
 386/bin/news - 775 sys sys 1168402341 71956
 386/bin/news - 775 sys sys 1168402341 71956
@@ -7722,7 +7722,7 @@ sys/man/4/INDEX - 664 sys sys 1196638942 1026
 sys/man/4/INDEX.html - 664 sys sys 1196638942 5147
 sys/man/4/INDEX.html - 664 sys sys 1196638942 5147
 sys/man/4/acme - 664 sys sys 1196638943 10435
 sys/man/4/acme - 664 sys sys 1196638943 10435
 sys/man/4/archfs - 664 sys sys 1196638943 533
 sys/man/4/archfs - 664 sys sys 1196638943 533
-sys/man/4/cdfs - 664 sys sys 1205857355 4480
+sys/man/4/cdfs - 664 sys sys 1206047086 4636
 sys/man/4/cfs - 664 sys sys 1196638943 2136
 sys/man/4/cfs - 664 sys sys 1196638943 2136
 sys/man/4/consolefs - 664 sys sys 1196638943 4389
 sys/man/4/consolefs - 664 sys sys 1196638943 4389
 sys/man/4/cwfs - 664 sys sys 1196638943 6553
 sys/man/4/cwfs - 664 sys sys 1196638943 6553
@@ -8178,7 +8178,7 @@ sys/src/9/pc/screen.h - 664 sys sys 1147023549 4256
 sys/src/9/pc/sd53c8xx.c - 664 sys sys 1170456695 55276
 sys/src/9/pc/sd53c8xx.c - 664 sys sys 1170456695 55276
 sys/src/9/pc/sd53c8xx.i - 664 sys sys 1128547230 28453
 sys/src/9/pc/sd53c8xx.i - 664 sys sys 1128547230 28453
 sys/src/9/pc/sd53c8xx.n - 664 sys sys 1131290556 12657
 sys/src/9/pc/sd53c8xx.n - 664 sys sys 1131290556 12657
-sys/src/9/pc/sdata.c - 664 sys sys 1202251523 53036
+sys/src/9/pc/sdata.c - 664 sys sys 1205986828 53185
 sys/src/9/pc/sdiahci.c - 664 sys sys 1200348596 38496
 sys/src/9/pc/sdiahci.c - 664 sys sys 1200348596 38496
 sys/src/9/pc/sdmv50xx.c - 664 sys sys 1204232564 34031
 sys/src/9/pc/sdmv50xx.c - 664 sys sys 1204232564 34031
 sys/src/9/pc/sdmylex.c - 664 sys sys 1189229947 28395
 sys/src/9/pc/sdmylex.c - 664 sys sys 1189229947 28395
@@ -10019,11 +10019,11 @@ sys/src/cmd/cc/sub.c - 664 sys sys 1143759345 34268
 sys/src/cmd/cc/y.tab.h - 664 sys sys 1098501521 1680
 sys/src/cmd/cc/y.tab.h - 664 sys sys 1098501521 1680
 sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
 sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
 sys/src/cmd/cdfs/buf.c - 664 sys sys 1205271166 1923
 sys/src/cmd/cdfs/buf.c - 664 sys sys 1205271166 1923
-sys/src/cmd/cdfs/dat.h - 664 sys sys 1205470094 4603
+sys/src/cmd/cdfs/dat.h - 664 sys sys 1206046829 4619
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
-sys/src/cmd/cdfs/main.c - 664 sys sys 1205470095 11592
+sys/src/cmd/cdfs/main.c - 664 sys sys 1206046865 12396
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
-sys/src/cmd/cdfs/mmc.c - 664 sys sys 1205470177 30641
+sys/src/cmd/cdfs/mmc.c - 664 sys sys 1206046883 32136
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
 sys/src/cmd/cec/LICENSE - 664 sys sys 1186248056 1554
 sys/src/cmd/cec/LICENSE - 664 sys sys 1186248056 1554
 sys/src/cmd/cec/Protocol - 664 sys sys 1186248056 2881
 sys/src/cmd/cec/Protocol - 664 sys sys 1186248056 2881
@@ -12848,7 +12848,7 @@ sys/src/cmd/ndb/mkdb.c - 664 sys sys 957402054 2886
 sys/src/cmd/ndb/mkfile - 664 sys sys 1205354106 2000
 sys/src/cmd/ndb/mkfile - 664 sys sys 1205354106 2000
 sys/src/cmd/ndb/mkhash.c - 664 sys sys 1014926160 2899
 sys/src/cmd/ndb/mkhash.c - 664 sys sys 1014926160 2899
 sys/src/cmd/ndb/mkhosts.c - 664 sys sys 957402054 4294
 sys/src/cmd/ndb/mkhosts.c - 664 sys sys 957402054 4294
-sys/src/cmd/ndb/query.c - 664 sys sys 1188422202 1793
+sys/src/cmd/ndb/query.c - 664 sys sys 1205986702 1913
 sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
 sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
 sys/src/cmd/news.c - 664 sys sys 1014926614 3778
 sys/src/cmd/news.c - 664 sys sys 1014926614 3778
 sys/src/cmd/nfs.c - 664 sys sys 1050068720 31096
 sys/src/cmd/nfs.c - 664 sys sys 1050068720 31096
@@ -15873,5 +15873,3 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
-sys/src/9/pc/sdata.c - 664 sys sys 1205986828 53185
-sys/src/cmd/ndb/query.c - 664 sys sys 1205986702 1913

+ 6 - 6
dist/replica/plan9.db

@@ -172,7 +172,7 @@
 386/bin/calendar - 775 sys sys 1200262736 79060
 386/bin/calendar - 775 sys sys 1200262736 79060
 386/bin/cat - 775 sys sys 1148500611 37482
 386/bin/cat - 775 sys sys 1148500611 37482
 386/bin/cb - 775 sys sys 1168402293 77628
 386/bin/cb - 775 sys sys 1168402293 77628
-386/bin/cdfs - 775 sys sys 1205524026 171999
+386/bin/cdfs - 775 sys sys 1206069507 173352
 386/bin/cec - 775 sys sys 1193714267 75896
 386/bin/cec - 775 sys sys 1193714267 75896
 386/bin/cfs - 775 sys sys 1190863294 130565
 386/bin/cfs - 775 sys sys 1190863294 130565
 386/bin/chgrp - 775 sys sys 1168402294 59522
 386/bin/chgrp - 775 sys sys 1168402294 59522
@@ -353,7 +353,7 @@
 386/bin/ndb/mkdb - 775 sys sys 1168402340 64211
 386/bin/ndb/mkdb - 775 sys sys 1168402340 64211
 386/bin/ndb/mkhash - 775 sys sys 1178568296 83312
 386/bin/ndb/mkhash - 775 sys sys 1178568296 83312
 386/bin/ndb/mkhosts - 775 sys sys 1178568296 84355
 386/bin/ndb/mkhosts - 775 sys sys 1178568296 84355
-386/bin/ndb/query - 775 sys sys 1188447268 82960
+386/bin/ndb/query - 775 sys sys 1206042296 83761
 386/bin/netkey - 775 sys sys 1168402341 72717
 386/bin/netkey - 775 sys sys 1168402341 72717
 386/bin/netstat - 775 sys sys 1204292542 86477
 386/bin/netstat - 775 sys sys 1204292542 86477
 386/bin/news - 775 sys sys 1168402341 71956
 386/bin/news - 775 sys sys 1168402341 71956
@@ -7722,7 +7722,7 @@ sys/man/4/INDEX - 664 sys sys 1196638942 1026
 sys/man/4/INDEX.html - 664 sys sys 1196638942 5147
 sys/man/4/INDEX.html - 664 sys sys 1196638942 5147
 sys/man/4/acme - 664 sys sys 1196638943 10435
 sys/man/4/acme - 664 sys sys 1196638943 10435
 sys/man/4/archfs - 664 sys sys 1196638943 533
 sys/man/4/archfs - 664 sys sys 1196638943 533
-sys/man/4/cdfs - 664 sys sys 1205857355 4480
+sys/man/4/cdfs - 664 sys sys 1206047086 4636
 sys/man/4/cfs - 664 sys sys 1196638943 2136
 sys/man/4/cfs - 664 sys sys 1196638943 2136
 sys/man/4/consolefs - 664 sys sys 1196638943 4389
 sys/man/4/consolefs - 664 sys sys 1196638943 4389
 sys/man/4/cwfs - 664 sys sys 1196638943 6553
 sys/man/4/cwfs - 664 sys sys 1196638943 6553
@@ -10019,11 +10019,11 @@ sys/src/cmd/cc/sub.c - 664 sys sys 1143759345 34268
 sys/src/cmd/cc/y.tab.h - 664 sys sys 1098501521 1680
 sys/src/cmd/cc/y.tab.h - 664 sys sys 1098501521 1680
 sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
 sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
 sys/src/cmd/cdfs/buf.c - 664 sys sys 1205271166 1923
 sys/src/cmd/cdfs/buf.c - 664 sys sys 1205271166 1923
-sys/src/cmd/cdfs/dat.h - 664 sys sys 1205470094 4603
+sys/src/cmd/cdfs/dat.h - 664 sys sys 1206046829 4619
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
-sys/src/cmd/cdfs/main.c - 664 sys sys 1205470095 11592
+sys/src/cmd/cdfs/main.c - 664 sys sys 1206046865 12396
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
-sys/src/cmd/cdfs/mmc.c - 664 sys sys 1205470177 30641
+sys/src/cmd/cdfs/mmc.c - 664 sys sys 1206046883 32136
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
 sys/src/cmd/cec/LICENSE - 664 sys sys 1186248056 1554
 sys/src/cmd/cec/LICENSE - 664 sys sys 1186248056 1554
 sys/src/cmd/cec/Protocol - 664 sys sys 1186248056 2881
 sys/src/cmd/cec/Protocol - 664 sys sys 1186248056 2881

+ 6 - 0
dist/replica/plan9.log

@@ -18827,3 +18827,9 @@
 1205985604 0 c sys/man/6/style - 664 sys sys 1205985568 2659
 1205985604 0 c sys/man/6/style - 664 sys sys 1205985568 2659
 1205987404 0 c sys/src/9/pc/sdata.c - 664 sys sys 1205986828 53185
 1205987404 0 c sys/src/9/pc/sdata.c - 664 sys sys 1205986828 53185
 1205987404 1 c sys/src/cmd/ndb/query.c - 664 sys sys 1205986702 1913
 1205987404 1 c sys/src/cmd/ndb/query.c - 664 sys sys 1205986702 1913
+1206043204 0 c 386/bin/ndb/query - 775 sys sys 1206042296 83761
+1206046804 0 c sys/src/cmd/cdfs/dat.h - 664 sys sys 1206046829 4619
+1206046804 1 c sys/src/cmd/cdfs/main.c - 664 sys sys 1206046865 12396
+1206046804 2 c sys/src/cmd/cdfs/mmc.c - 664 sys sys 1206046883 32136
+1206048605 0 c sys/man/4/cdfs - 664 sys sys 1206047086 4636
+1206070204 0 c 386/bin/cdfs - 775 sys sys 1206069507 173352

+ 4 - 0
sys/man/4/cdfs

@@ -117,6 +117,9 @@ Blank the entire rewritable disc in the drive.
 Blank only the table of contents on the rewritable
 Blank only the table of contents on the rewritable
 disc in the drive.
 disc in the drive.
 .TP
 .TP
+.B closetracks
+Close any open tracks on the current disc but do not finalize (fixate) the disc.
+.TP
 .B eject
 .B eject
 Eject the disc in the drive.
 Eject the disc in the drive.
 .TP
 .TP
@@ -156,6 +159,7 @@ an internet CD database
 to get a table of contents.
 to get a table of contents.
 Subsequent lines contain the current and maximum
 Subsequent lines contain the current and maximum
 reading and writing speeds.
 reading and writing speeds.
+Additional lines may further describe the current disc.
 .PD
 .PD
 .PP
 .PP
 .I Aux/cddb
 .I Aux/cddb

+ 1 - 0
sys/src/cmd/cdfs/dat.h

@@ -166,6 +166,7 @@ struct Drive
 
 
 	/* disc characteristics */
 	/* disc characteristics */
 	int	mmctype;
 	int	mmctype;
+	char	*dvdtype;
 	int	firsttrack;
 	int	firsttrack;
 	int	ntrack;
 	int	ntrack;
 	int	nchange;		/* compare with the members in Scsi */
 	int	nchange;		/* compare with the members in Scsi */

+ 49 - 12
sys/src/cmd/cdfs/main.c

@@ -15,6 +15,8 @@ struct Aux {
 	Otrack	*o;
 	Otrack	*o;
 };
 };
 
 
+ulong	getnwa(Drive *);
+
 static void checktoc(Drive*);
 static void checktoc(Drive*);
 
 
 int vflag;
 int vflag;
@@ -111,9 +113,8 @@ fswalk1(Fid *fid, char *name, Qid *qid)
 		for(i=0; i<drive->ntrack; i++)
 		for(i=0; i<drive->ntrack; i++)
 			if(strcmp(drive->track[i].name, name) == 0)
 			if(strcmp(drive->track[i].name, name) == 0)
 				break;
 				break;
-		if(i == drive->ntrack) {
+		if(i == drive->ntrack)
 			return "file not found";
 			return "file not found";
-		}
 		*qid = (Qid){Qtrack+i, 0, 0};
 		*qid = (Qid){Qtrack+i, 0, 0};
 		return nil;
 		return nil;
 
 
@@ -291,8 +292,8 @@ diskid(Drive *d)
 	tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
 	tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
 
 
 	/*
 	/*
-	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is correct.
-	 * most CDs are in the database under both entries.
+	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is
+	 * correct.  most CDs are in the database under both entries.
 	 */
 	 */
 	return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);
 	return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);
 }
 }
@@ -301,33 +302,69 @@ static void
 readctl(Req *r)
 readctl(Req *r)
 {
 {
 	int i, isaudio;
 	int i, isaudio;
+	char *p, *e;
 	char s[1024];
 	char s[1024];
 	Msf *m;
 	Msf *m;
 
 
-	strcpy(s, "");
-
 	isaudio = 0;
 	isaudio = 0;
 	for(i=0; i<drive->ntrack; i++)
 	for(i=0; i<drive->ntrack; i++)
 		if(drive->track[i].type == TypeAudio)
 		if(drive->track[i].type == TypeAudio)
 			isaudio = 1;
 			isaudio = 1;
 
 
+	p = s;
+	e = s + sizeof s;
+	*p = '\0';
 	if(isaudio){
 	if(isaudio){
-		sprint(s, "aux/cddb query %8.8lux %d", diskid(drive), drive->ntrack);
+		p = seprint(p, e, "aux/cddb query %8.8lux %d", diskid(drive),
+			drive->ntrack);
 		for(i=0; i<drive->ntrack; i++){
 		for(i=0; i<drive->ntrack; i++){
 			m = &drive->track[i].mbeg;
 			m = &drive->track[i].mbeg;
-			sprint(s+strlen(s), " %d", (m->m*60+m->s)*75+m->f);
+			p = seprint(p, e, " %d", (m->m*60 + m->s)*75 + m->f);
 		}
 		}
 		m = &drive->track[drive->ntrack].mbeg;
 		m = &drive->track[drive->ntrack].mbeg;
-		sprint(s+strlen(s), " %d\n", m->m*60+m->s);
+		p = seprint(p, e, " %d\n", m->m*60 + m->s);
 	}
 	}
 
 
 	if(drive->readspeed == drive->writespeed)
 	if(drive->readspeed == drive->writespeed)
-		sprint(s+strlen(s), "speed %d\n", drive->readspeed);
+		p = seprint(p, e, "speed %d\n", drive->readspeed);
 	else
 	else
-		sprint(s+strlen(s), "speed read %d write %d\n",
+		p = seprint(p, e, "speed read %d write %d\n",
 			drive->readspeed, drive->writespeed);
 			drive->readspeed, drive->writespeed);
-	sprint(s+strlen(s), "maxspeed read %d write %d\n",
+	p = seprint(p, e, "maxspeed read %d write %d\n",
 		drive->maxreadspeed, drive->maxwritespeed);
 		drive->maxreadspeed, drive->maxwritespeed);
+
+	if (drive->Scsi.changetime != 0 && drive->ntrack != 0) { /* have disc? */
+		switch (drive->mmctype) {
+		case Mmccd:
+			p = seprint(p, e, "cd-");
+			break;
+		case Mmcdvdminus:
+		case Mmcdvdplus:
+			p = seprint(p, e, "%s", drive->dvdtype);
+			break;
+		case Mmcbd:
+			p = seprint(p, e, "bd-");
+			break;
+		case Mmcnone:
+			p = seprint(p, e, "no disc");
+			break;
+		default:
+			p = seprint(p, e, "**GOK**");
+			break;
+		}
+		if (drive->mmctype != Mmcnone) {
+			if (drive->dvdtype == nil)
+				if (drive->erasable)
+					p = seprint(p, e, "rw");
+				else if (drive->recordable)
+					p = seprint(p, e, "r");
+				else
+					p = seprint(p, e, "rom");
+			p = seprint(p, e, " next writable sector %lud",
+				getnwa(drive));
+		}
+		seprint(p, e, "\n");
+	}
 	readstr(r, s);
 	readstr(r, s);
 }
 }
 
 

+ 76 - 9
sys/src/cmd/cdfs/mmc.c

@@ -77,6 +77,15 @@ biges(void *p)
 	return (a[0]<<8) | a[1];
 	return (a[0]<<8) | a[1];
 }
 }
 
 
+ulong
+getnwa(Drive *drive)
+{
+	Mmcaux *aux;
+
+	aux = drive->aux;
+	return aux->mmcnwa;
+}
+
 static void
 static void
 hexdump(void *v, int n)
 hexdump(void *v, int n)
 {
 {
@@ -488,7 +497,7 @@ mmctrackinfo(Drive *drive, int t, int i)
 //	dmode = resp[6] & 0x0F;
 //	dmode = resp[6] & 0x0F;
 
 
 	if(vflag)
 	if(vflag)
-		print("track %d type %d (%s)\n", t, tmode,
+		print("track %d type %d (%s)", t, tmode,
 			(tmode < nelem(tracktype)? tracktype[tmode]: "**GOK**"));
 			(tmode < nelem(tracktype)? tracktype[tmode]: "**GOK**"));
 	type = TypeNone;
 	type = TypeNone;
 	bs = BScdda;
 	bs = BScdda;
@@ -522,13 +531,22 @@ mmctrackinfo(Drive *drive, int t, int i)
 	drive->track[i].bs = bs;
 	drive->track[i].bs = bs;
 	drive->track[i].size = (vlong)(size-2) * bs;	/* -2: skip lead out */
 	drive->track[i].size = (vlong)(size-2) * bs;	/* -2: skip lead out */
 
 
-	if(resp[6] & (1<<6)) {
+	if(resp[6] & (1<<6)) {			/* blank? */
 		drive->track[i].type = TypeBlank;
 		drive->track[i].type = TypeBlank;
 		drive->writeok = 1;
 		drive->writeok = 1;
 	}
 	}
 
 
-	if(t == Invistrack)
+	if(vflag)
+		print(" start %lud end %lud", beg, beg + size - 1);
+	/* resp[6] & (1<<7) of zero: invisible track */
+	/* t == getinvistrack(): invisible track */
+	if(t == Invistrack || resp[7] & 1) {	/* invis or nwa valid? */
 		aux->mmcnwa = bige(&resp[12]);
 		aux->mmcnwa = bige(&resp[12]);
+		if (vflag)
+			print(" nwa %lud", aux->mmcnwa);
+	}
+	if (vflag)
+		print("\n");
 	return 0;
 	return 0;
 }
 }
 
 
@@ -621,6 +639,7 @@ getdvdstruct(Drive *drive)
 	cat = (resp[4] & 0xf0) >> 4;	/* disk category, MMC-6 §6.22.3.2.1 */
 	cat = (resp[4] & 0xf0) >> 4;	/* disk category, MMC-6 §6.22.3.2.1 */
 	if (vflag)
 	if (vflag)
 		fprint(2, "dvd type is %s\n", dvdtype[cat]);
 		fprint(2, "dvd type is %s\n", dvdtype[cat]);
+	drive->dvdtype = dvdtype[cat];
 	/* write parameters mode page may suffice to compute writeok for dvd */
 	/* write parameters mode page may suffice to compute writeok for dvd */
 	drive->erasable = drive->recordable = 0;
 	drive->erasable = drive->recordable = 0;
 	/*
 	/*
@@ -821,6 +840,7 @@ mmcgettoc(Drive *drive)
 	}
 	}
 
 
 	drive->mmctype = Mmcnone;
 	drive->mmctype = Mmcnone;
+	drive->dvdtype = nil;
 	getdvdstruct(drive);
 	getdvdstruct(drive);
 	getbdstruct(drive);
 	getbdstruct(drive);
 	if (drive->mmctype == Mmcnone)
 	if (drive->mmctype == Mmcnone)
@@ -1237,6 +1257,7 @@ mmccreate(Drive *drive, int type)
 
 
 /*
 /*
  * issue some form of close track, close session or finalize disc command.
  * issue some form of close track, close session or finalize disc command.
+ * see The Matrix, table 252 in MMC-6 §6.3.2.3.
  */
  */
 static int
 static int
 mmcxclose(Drive *drive, int clf, int trackno)
 mmcxclose(Drive *drive, int clf, int trackno)
@@ -1307,6 +1328,48 @@ mmcclose(Otrack *o)
 	free(o);
 	free(o);
 }
 }
 
 
+/*
+ * just close the current tracks.
+ */
+static int
+closetracks(Drive *drive)
+{
+	int r, invis;
+	uchar *p;
+	Mmcaux *aux;
+
+	if (drive->mmctype == Mmcdvdplus && drive->erasable) {
+		werrstr("dvd+rw can't close tracks without finalizing");
+		return -1;
+	}
+	if((drive->cap & Cwrite) == 0) {
+		werrstr("drive not a writer");
+		return -1;
+	}
+	drive->nchange = -1;		/* force reread toc */
+
+	/* page 5 is legacy and now read-only; see MMC-6 §7.5.4.1 */
+	aux = drive->aux;
+	p = aux->page05;
+	/*
+	 * p[3] is multi-session / fp / copy / track mode.
+	 * zero multi-session field: next session not allowed.
+	 */
+	p[3] &= ~0xC0;
+	/* try to set it but don't freak out if it fails */
+	mmcsetpage(drive, Pagwrparams, p);
+
+	invis = getinvistrack(drive);
+	if (invis < 0)
+		invis = Invistrack;
+	if (vflag)
+		fprint(2, "closing invis track %d...\n", invis);
+	r = mmcxclose(drive, Closetrack, invis);
+	if (vflag)
+		fprint(2, "... done.\n");
+	return r;
+}
+
 /*
 /*
  * close the current session, then finalize the disc.
  * close the current session, then finalize the disc.
  */
  */
@@ -1381,18 +1444,22 @@ e(int status)
 static char*
 static char*
 mmcctl(Drive *drive, int argc, char **argv)
 mmcctl(Drive *drive, int argc, char **argv)
 {
 {
+	char *cmd;
+
 	if(argc < 1)
 	if(argc < 1)
 		return nil;
 		return nil;
-
-	if(strcmp(argv[0], "format") == 0)
+	cmd = argv[0];
+	if(strcmp(cmd, "format") == 0)
 		return e(format(drive));
 		return e(format(drive));
-	if(strcmp(argv[0], "blank") == 0)
+	if(strcmp(cmd, "blank") == 0)
 		return e(mmcblank(drive, 0));
 		return e(mmcblank(drive, 0));
-	if(strcmp(argv[0], "quickblank") == 0)
+	if(strcmp(cmd, "quickblank") == 0)
 		return e(mmcblank(drive, 1));
 		return e(mmcblank(drive, 1));
-	if(strcmp(argv[0], "eject") == 0)
+	if(strcmp(cmd, "closetracks") == 0)
+		return e(closetracks(drive));
+	if(strcmp(cmd, "eject") == 0)
 		return e(start(drive, 2));
 		return e(start(drive, 2));
-	if(strcmp(argv[0], "ingest") == 0)
+	if(strcmp(cmd, "ingest") == 0)
 		return e(start(drive, 3));
 		return e(start(drive, 3));
 	return "bad arg";
 	return "bad arg";
 }
 }