henesyinit from lsubb0c8bdb6 years agoHistory
418 lines · 6.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <fcall.h>#include <auth.h>#include <9p.h>#include <b.h> typedef struct Fproto Fproto; enum {	Stack	= 16 * 1024, }; struct Fproto {	char*	name;	int	mode;	int	id;};  Req*	wreqs;QLock	wreqslck;int	waitingwreq;int	afd = -1;char*	addr; enum {	Qaudio,	Qvolume,}; Fproto	mp3dir[] = {	{ "audio",  0222, Qaudio },	{ "volume", 0666, Qvolume },}; Fproto	prgdir[] = {	{ "output",  0222, Qaudio },}; #define dprint	if(debug)fprintstatic int	debug;  static char*	playcmd = "mpeg3play -";static char*	vname = "/devs/audio";static int	mp3fd = -1;static int	playerpid = -1; static int	wflag;	// close the player after each writestatic int	vflag;	// provide volume ctl file static voidaddwreq(Req* r){	qlock(&wreqslck);	if (waitingwreq){		rendezvous(0, r);		waitingwreq = 0;	} else {		r->aux = wreqs;		wreqs = r;	}	qunlock(&wreqslck);} static Req*getwreq(void){	Req**	l;	Req*	r; 	qlock(&wreqslck);	for (l = &wreqs; *l != nil && (*l)->aux != nil; l = &((*l)->aux))		;	if (*l == nil){		waitingwreq = 1;		qunlock(&wreqslck);		r = (Req*)rendezvous(0, 0);		return r;	} else {		r = *l;		*l = nil;		qunlock(&wreqslck);	}	return r;} intfileclass(File* fp){	return ((fp->qid.path&0xff000000)>>24);} voidpopulate(File* d, Fproto* ent, int nent){	int	i;	File*	f; 	for (i = 0; i <nent; i++, ent++){		f = createfile(d, ent->name, d->uid, ent->mode, nil);		f->qid.path |= ((ent->id&0xff)<<24);		closefile(f);	}} voidmkfs(Srv* srv, Fproto* ent, int nent, int dmode){	assert(srv->tree == nil);	srv->tree =  alloctree(nil, nil, DMDIR|dmode, nil);	populate(srv->tree->root, ent, nent);} voidstopplayer(int kill){	dprint(2, "stopplayer\n");	if (mp3fd >= 0)		close(mp3fd);	mp3fd = -1;	if (kill){		if (playerpid != -1)			postnote(PNGROUP, playerpid, "kill");		playerpid = -1;	}}  intstartplayer(void){	int	fd[2];	int	i; 	dprint(2, "startplayer\n");	pipe(fd);	switch(playerpid = rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)){	case -1:		close(fd[0]);		close(fd[1]);		break;	case 0:		rfork(RFNOTEG);		close(fd[1]);		dup(fd[0], 0);		close(fd[0]);		for (i = 3; i < 50; i++)			close(i);		execl("/bin/rc", "rc", "-c", playcmd, nil);		exits("exec");		break;	default:		close(fd[0]);		mp3fd = fd[1];	}	return mp3fd;} intsafewrite(int fd, Req* r){	int	pid;	Waitmsg*m;	int	ok; 	r->ofcall.count = 0;	switch(pid = rfork(RFPROC|RFMEM)){	case 0:		r->ofcall.count = write(fd, r->ifcall.data, r->ifcall.count);		exits(0);	case -1:		sysfatal("safewrite");	default:		m = wait();		if (m && m->pid == pid)			ok = !m->msg[0];		else			ok = 0;		free(m);		return ok;	}} static voidwriteproc(void){	Req*	r; 	for(;;){		r = getwreq();		dprint(2, "getwreq\n");		assert(r);		if (r->ifcall.offset == 0)			stopplayer(1);		if (mp3fd < 0)			mp3fd = startplayer();		if (mp3fd >= 0){			if (!safewrite(mp3fd, r))				stopplayer(0);		}		if (wflag)			stopplayer(0);		respond(r, nil);	}} static voidfsread(Req* r){	File* file;	char*	buf;	int	id; 	if (r->fid->qid.type&QTAUTH){		authread(r);		return;	}	file = r->fid->file;	id = fileclass(file);	switch(id){	case Qaudio:		respond(r, "bug: read of audio");		break;	case Qvolume:		buf = readfstr("/dev/volume");		readstr(r, buf ? buf : "");		free(buf);		break;	default:		respond(r, "bug: fsread: bad id");	} } static voidfswrite(Req* r){	File* file;	int	id; 	if (r->fid->qid.type&QTAUTH){		authwrite(r);		return;	}	file = r->fid->file;	id = fileclass(file);	switch(id){	case Qaudio:		addwreq(r);		break;	case Qvolume:		assert(vflag);		writef("/dev/volume", r->ifcall.data, r->ifcall.count);		r->ofcall.count = r->ifcall.count;		respond(r, nil);		break;	default:		respond(r, "bug: bad id in fspread");	}} static voidfsattach(Req* r){	if (r->srv->auth != nil && authattach(r) < 0)		return;	respond(r, nil);} static voidfsopen(Req* r){ 	if (r->fid->qid.type&QTAUTH)		sysfatal("fsopen for an AUTH file. fixme: add respond/return\n");	respond(r, nil);} static voidfsclunk(Fid* fid){ 	if (fid->qid.type&QTAUTH)		authdestroy(fid);} static intislocal(char* addr){	static char*	l = nil;	if (addr == nil)		return 1;	if (!strncmp(addr, "::", 2) || !strncmp(addr, "127.0.0.1", 8))		return 1;	if (l == nil)		l = getenv("sysaddr");	if (l && !strncmp(addr, l, strlen(l)))		return 1;	return 0;} static voidbauth9p(Req* r){	if (islocal(r->srv->addr)) {		r->srv->auth = nil;	// no auth here any more		respond(r, "auth no required for local peers");	} else		auth9p(r);} static Srv sfs={	.auth	=	bauth9p,	.attach	=	fsattach,	.open	=	fsopen,	.read	=	fsread,	.write	=	fswrite,	.destroyfid = 	fsclunk,}; static voidannounceproc(void){	int	afd = -1; 	for(;;){		afd = announcevol(afd, addr, vname, nil);		sleep(10 * 1000);	}} voidusage(void){	fprint(2, "usage: %s [-abcdADwv] [-V name] [-s srv] [-m mnt] [-n addr] [-p playcmd]\n", argv0);	exits("usage");} voidmain(int argc, char **argv){	char*	mnt;	char*	srv;	int	mflag; 	srv = nil;	mnt = nil;	mflag = MREPL|MCREATE;	ARGBEGIN{	case 'a':		mflag = MAFTER|MCREATE;		break;	case 'b':		mflag = MBEFORE|MCREATE;		break;	case 'c':		mflag = MREPL|MCREATE;		break;	case 'A':		sfs.auth = nil;		break;	case 'D':		chatty9p++;	case 'd':		debug++;		break;	case 's':		srv = EARGF(usage());		break;	case 'm':		mnt = EARGF(usage());		break;	case 'n':		addr = EARGF(usage());		break;	case 'p':		playcmd = EARGF(usage());		break;	case 'w':		wflag = 1;		break;	case 'v':		vflag = 1;		break;	case 'V':		vname = EARGF(usage());		break;	default:		usage();	}ARGEND; 	if (argc != 0)		usage(); 	if (srv == nil && mnt == nil && addr == nil)		addr=smprint("tcp!%s!11004", sysname()); 	if (vflag)		mkfs(&sfs, mp3dir, nelem(mp3dir), 0555);	else		mkfs(&sfs, prgdir, nelem(prgdir), 0555);	if (rfork(RFPROC|RFMEM|RFNOWAIT) == 0)		writeproc();	if (addr != nil)		listensrv(&sfs, addr);	if (srv != nil || mnt != nil)		postmountsrv(&sfs, srv, mnt, mflag);	if (addr != nil && vname != nil){		if (rfork(RFPROC|RFMEM|RFNOWAIT) == 0)			announceproc();	}	exits(0);}