⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apm.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
estrdupn(char *s, int n){	int l;	char *t;	l = strlen(s);	if(l > n)		l = n;	t = emalloc(l+1);	memmove(t, s, l);	t[l] = '\0';	setmalloctag(t, getcallerpc(&s));	return t;}enum {	Qroot = 0,	Qevent,	Qbattery,	Qctl,};static void rootread(Req*);static void eventread(Req*);static void ctlread(Req*);static void ctlwrite(Req*);static void batteryread(Req*);typedef struct Dfile Dfile;struct Dfile {	Qid qid;	char *name;	ulong mode;	void (*read)(Req*);	void (*write)(Req*);};Dfile dfile[] = {	{ {Qroot,0,QTDIR},		"/",		DMDIR|0555,	rootread,		nil, },	{ {Qevent},		"event",	0444,		eventread,	nil, },	{ {Qbattery},	"battery",	0444,		batteryread,	nil, },	{ {Qctl},		"ctl",		0666,		ctlread,		ctlwrite, },};static intfillstat(uvlong path, Dir *d, int doalloc){	int i;	for(i=0; i<nelem(dfile); i++)		if(path==dfile[i].qid.path)			break;	if(i==nelem(dfile))		return -1;	memset(d, 0, sizeof *d);	d->uid = doalloc ? estrdup("apm") : "apm";	d->gid = doalloc ? estrdup("apm") : "apm";	d->length = 0;	d->name = doalloc ? estrdup(dfile[i].name) : dfile[i].name;	d->mode = dfile[i].mode;	d->atime = d->mtime = time(0);	d->qid = dfile[i].qid;	return 0;}static char*fswalk1(Fid *fid, char *name, Qid *qid){	int i;	if(strcmp(name, "..")==0){		*qid = dfile[0].qid;		fid->qid = *qid;		return nil;	}	for(i=1; i<nelem(dfile); i++){	/* i=1: 0 is root dir */		if(strcmp(dfile[i].name, name)==0){			*qid = dfile[i].qid;			fid->qid = *qid;			return nil;		}	}	return "file does not exist";}static voidfsopen(Req *r){	switch((ulong)r->fid->qid.path){	case Qroot:		r->fid->aux = (void*)0;		respond(r, nil);		return;	case Qevent:	case Qbattery:		if(r->ifcall.mode == OREAD){			respond(r, nil);			return;		}		break;	case Qctl:		if((r->ifcall.mode&~(OTRUNC|OREAD|OWRITE|ORDWR)) == 0){			respond(r, nil);			return;		}		break;	}	respond(r, "permission denied");	return;}static voidfsstat(Req *r){	fillstat(r->fid->qid.path, &r->d, 1);	respond(r, nil);}static voidfsread(Req *r){	dfile[r->fid->qid.path].read(r);}static voidfswrite(Req *r){	dfile[r->fid->qid.path].write(r);}static voidrootread(Req *r){	int n;	uvlong offset;	char *p, *ep;	Dir d;	if(r->ifcall.offset == 0)		offset = 0;	else		offset = (uvlong)r->fid->aux;	p = r->ofcall.data;	ep = r->ofcall.data+r->ifcall.count;	if(offset == 0)		/* skip root */		offset = 1;	for(; p+2 < ep; p+=n){		if(fillstat(offset, &d, 0) < 0)			break;		n = convD2M(&d, (uchar*)p, ep-p);		if(n <= BIT16SZ)			break;		offset++;	}	r->fid->aux = (void*)offset;	r->ofcall.count = p - r->ofcall.data;	respond(r, nil);}static voidbatteryread(Req *r){	char buf[Mbattery*80], *ep, *p;	int i;	apmgetpowerstatus(&apm, DevAll);	p = buf;	ep = buf+sizeof buf;	*p = '\0';	/* could be no batteries */	for(i=0; i<apm.nbattery && i<Mbattery; i++)		p += snprint(p, ep-p, "%s %d %d\n",			batterystatus(apm.battery[i].status),			apm.battery[i].percent, apm.battery[i].time);		readstr(r, buf);	respond(r, nil);}intiscmd(char *p, char *cmd){	int l;	l = strlen(cmd);	return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t';}char*skip(char *p, char *cmd){	p += strlen(cmd);	while(*p==' ' || *p=='\t')		p++;	return p;}static voidrespondx(Req *r, int c){	char err[ERRMAX];	if(c == 0)		respond(r, nil);	else{		rerrstr(err, sizeof err);		respond(r, err);	}}/* * we don't do suspend because it messes up the * cycle counter as well as the pcmcia ethernet cards. */static voidctlwrite(Req *r){	char buf[80], *p, *q;	int dev;	long count;	count = r->ifcall.count;	if(count > sizeof(buf)-1)		count = sizeof(buf)-1;	memmove(buf, r->ifcall.data, count);	buf[count] = '\0';	if(count && buf[count-1] == '\n'){		--count;		buf[count] = '\0';	}	q = buf;	p = strchr(q, ' ');	if(p==nil)		p = q+strlen(q);	else		*p++ = '\0';	if(strcmp(q, "")==0 || strcmp(q, "system")==0)		dev = DevAll;	else if(strcmp(q, "display")==0)		dev = DevDisplay;	else if(strcmp(q, "storage")==0)		dev = DevStorage;	else if(strcmp(q, "lpt")==0)		dev = DevLpt;	else if(strcmp(q, "eia")==0)		dev = DevEia;	else if(strcmp(q, "network")==0)		dev = DevNetwork;	else if(strcmp(q, "pcmcia")==0)		dev = DevPCMCIA;	else{		respond(r, "unknown device");		return;	}	if(strcmp(p, "enable")==0)		respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt));	else if(strcmp(p, "disable")==0)		respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt));	else if(strcmp(p, "standby")==0)		respondx(r, apmsetpowerstate(&apm, dev, PowerStandby));	else if(strcmp(p, "on")==0)		respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled));/*	else if(strcmp(p, "off")==0)		respondx(r, apmsetpowerstate(&apm, dev, PowerOff));*/	else if(strcmp(p, "suspend")==0)		respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend));	else		respond(r, "unknown verb");}static intstatusline(char *buf, int nbuf, char *name, int dev){	int s;	char *state;	state = "unknown";	if((s = apmgetpowerstate(&apm, dev)) >= 0)		state = powerstate(s);	return snprint(buf, nbuf, "%s %s\n", name, state);}static voidctlread(Req *r){	char buf[256+7*50], *ep, *p;	p = buf;	ep = buf+sizeof buf;	p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus));	p += snprint(p, ep-p, "capabilities");	if(apm.capabilities & CapStandby) 		p += snprint(p, ep-p, " standby");	if(apm.capabilities & CapSuspend) 		p += snprint(p, ep-p, " suspend");	if(apm.capabilities & CapSlowCpu)		p += snprint(p, ep-p, " slowcpu");	p += snprint(p, ep-p, "\n");	p += statusline(p, ep-p, "system", DevAll);	p += statusline(p, ep-p, "display", DevDisplay);	p += statusline(p, ep-p, "storage", DevStorage);	p += statusline(p, ep-p, "lpt", DevLpt);	p += statusline(p, ep-p, "eia", DevEia|All);	p += statusline(p, ep-p, "network", DevNetwork|All);	p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All);	USED(p);	readstr(r, buf);	respond(r, nil);}enum {	STACK = 16384,};Channel *creq;Channel *cflush;Channel *cevent;Req *rlist, **tailp;int rp, wp;int nopoll;char eventq[32][80];static voidflushthread(void*){	Req *r, *or, **rq;	threadsetname("flushthread");	while(r = recvp(cflush)){		or = r->oldreq;		for(rq=&rlist; *rq; rq=&(*rq)->aux){			if(*rq == or){				*rq = or->aux;				if(tailp==&or->aux)					tailp = rq;				respond(or, "interrupted");				break;			}		}		respond(r, nil);	}}static voidanswerany(void){	char *buf;	int l, m;	Req *r;	if(rlist==nil || rp==wp)		return;	while(rlist && rp != wp){		r = rlist;		rlist = r->aux;		if(rlist==nil)			tailp = &rlist;		l = 0;		buf = r->ofcall.data;		m = r->ifcall.count;		while(rp != wp){			if(l+strlen(eventq[rp]) <= m){				strcpy(buf+l, eventq[rp]);				l += strlen(buf+l);			}else if(l==0){				strncpy(buf, eventq[rp], m-1);				buf[m-1] = '\0';				l += m;			}else				break;			rp++;			if(rp == nelem(eventq))				rp = 0;		}		r->ofcall.count = l;		respond(r, nil);	}}static voideventwatch(void*){	int e, s;	threadsetname("eventwatch");	for(;;){		s = 0;		while((e = apmgetevent(&apm)) >= 0){			sendul(cevent, e);			s = 1;		}		if(s)			sendul(cevent, -1);		if(sleep(750) < 0)			break;	}}static voideventthread(void*){	int e;	threadsetname("eventthread");	for(;;){		while((e = recvul(cevent)) >= 0){			snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));			strcat(eventq[wp], "\n");			wp++;			if(wp==nelem(eventq))				wp = 0;			if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))				break;		}		answerany();	}}static voideventproc(void*){	Req *r;	threadsetname("eventproc");	creq = chancreate(sizeof(Req*), 0);	cevent = chancreate(sizeof(ulong), 0);	cflush = chancreate(sizeof(Req*), 0);	tailp = &rlist;	if(!nopoll)		proccreate(eventwatch, nil, STACK);	threadcreate(eventthread, nil, STACK);	threadcreate(flushthread, nil, STACK);	while(r = recvp(creq)){		*tailp = r;		r->aux = nil;		tailp = &r->aux;		answerany();	}}static voidfsflush(Req *r){	sendp(cflush, r);}static voideventread(Req *r){	sendp(creq, r);}static voidfsattach(Req *r){	char *spec;	static int first = 1;	spec = r->ifcall.aname;	if(first){		first = 0;		proccreate(eventproc, nil, STACK);	}	if(spec && spec[0]){		respond(r, "invalid attach specifier");		return;	}	r->fid->qid = dfile[0].qid;	r->ofcall.qid = dfile[0].qid;	respond(r, nil);}Srv fs = {.attach=	fsattach,.walk1=	fswalk1,.open=	fsopen,.read=	fsread,.write=	fswrite,.stat=	fsstat,.flush=	fsflush,};voidusage(void){	fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");	exits("usage");}voidthreadmain(int argc, char **argv){	char *dev, *mtpt, *srv;	dev = nil;	mtpt = "/mnt/apm";	srv = nil;	ARGBEGIN{	case 'A':		apmdebug = 1;		break;	case 'D':		chatty9p = 1;		break;	case 'P':		nopoll = 1;		break;	case 'd':		dev = EARGF(usage());		break;	case 'i':		fs.nopipe++;		fs.infd = 0;		fs.outfd = 1;		mtpt = nil;		break;	case 'm':		mtpt = EARGF(usage());		break;	case 's':		srv = EARGF(usage());		break;	}ARGEND	if(dev == nil){		if((apm.fd = open("/dev/apm", ORDWR)) < 0		&& (apm.fd = open("#P/apm", ORDWR)) < 0){			fprint(2, "open %s: %r\n", dev);			threadexitsall("open");		}	} else if((apm.fd = open(dev, ORDWR)) < 0){		fprint(2, "open %s: %r\n", dev);		threadexitsall("open");	}	if(apmversion(&apm) < 0){		fprint(2, "cannot get apm version: %r\n");		threadexitsall("apmversion");	}	if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){		fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);		threadexitsall("apmversion");	}	if(apmgetcapabilities(&apm) < 0)		fprint(2, "warning: cannot read apm capabilities: %r\n");	apminstallationcheck(&apm);	apmcpuidle(&apm);	rfork(RFNOTEG);	threadpostmountsrv(&fs, srv, mtpt, MREPL);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -