📄 apm.c
字号:
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 + -