/* * platform-specific interface */ #define Unknown win_Unknown #define UNICODE #include #include #include #undef Unknown #include "dat.h" #include "fns.h" #include "error.h" #include "r16.h" enum{ Qdir, Qarchctl, Qcputype, Qregquery, Qhostmem }; static Dirtab archtab[]={ ".", {Qdir, 0, QTDIR}, 0, 0555, "archctl", {Qarchctl, 0}, 0, 0444, "cputype", {Qcputype}, 0, 0444, "regquery", {Qregquery}, 0, 0666, "hostmem", {Qhostmem}, 0, 0444, }; typedef struct Value Value; struct Value { int type; int size; union { ulong w; vlong q; char data[1]; /* utf-8 */ }; }; typedef struct Regroot Regroot; struct Regroot { char* name; HKEY root; }; static Regroot roots[] = { {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT}, {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG}, {"HKEY_CURRENT_USER", HKEY_CURRENT_USER}, {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE}, {"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA}, {"HKEY_USERS", HKEY_USERS}, }; static struct { ulong mhz; int ncpu; char cpu[64]; } arch; static QLock reglock; static Value* getregistry(HKEY, Rune16*, Rune16*); static int nprocs(void); static void archinit(void) { Value *v; char *p; v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"ProcessorNameString"); if(v != nil){ snprint(arch.cpu, sizeof(arch.cpu), "%s", v->data); if((p = strrchr(arch.cpu, ' ')) != nil) for(; p >= arch.cpu && *p == ' '; p--) *p = '\0'; free(v); }else{ v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"VendorIdentifier"); if(v != nil){ snprint(arch.cpu, sizeof(arch.cpu), "%s", v->data); free(v); }else snprint(arch.cpu, sizeof(arch.cpu), "unknown"); } v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"~MHz"); if(v != nil){ arch.mhz = v->w; free(v); } arch.ncpu = nprocs(); } static int nprocs(void) { int n; char *p; Rune16 *r; Value *v; n = 0; for(;;){ p = smprint("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", n); if(waserror()){ free(p); nexterror(); } r = widen(p); free(p); v = getregistry(HKEY_LOCAL_MACHINE, r, L"~MHz"); free(r); if(v == nil) break; free(v); n++; } return n; } static Chan* archattach(char* spec) { return devattach('a', spec); } static Walkqid* archwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, archtab, nelem(archtab), devgen); } static int archstat(Chan* c, uchar *db, int n) { return devstat(c, db, n, archtab, nelem(archtab), devgen); } static Chan* archopen(Chan* c, int omode) { return devopen(c, omode, archtab, nelem(archtab), devgen); } static void archclose(Chan* c) { if((ulong)c->qid.path == Qregquery && c->aux != nil) free(c->aux); } static long archread(Chan* c, void* a, long n, vlong offset) { char *p; Value *v; int i, l; MEMORYSTATUS mem; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, a, n, archtab, nelem(archtab), devgen); case Qarchctl: case Qcputype: l = 0; if((ulong)c->qid.path == Qcputype) l = 4; p = smalloc(READSTR); if(waserror()){ free(p); nexterror(); } snprint(p, READSTR, "cpu %q %lud %d\n", arch.cpu, arch.mhz, arch.ncpu); n = readstr(offset, a, n, p+l); poperror(); free(p); break; case Qregquery: v = c->aux; if(v == nil) return 0; p = smalloc(READSTR); if(waserror()){ free(p); nexterror(); } switch(v->type){ case REG_NONE: n = readstr(offset, a, n, "nil"); break; case REG_DWORD: snprint(p, READSTR, "int %ld", v->w); n = readstr(offset, a, n, p); break; #ifdef REG_QWORD case REG_QWORD: snprint(p, READSTR, "int %lld", v->q); n = readstr(offset, a, n, p); break; #endif case REG_SZ: case REG_EXPAND_SZ: if(v->data[0]) snprint(p, READSTR, "str %q", v->data); n = readstr(offset, a, n, p); break; case REG_MULTI_SZ: l = snprint(p, READSTR, "str"); for(i=0;;){ l += snprint(p+l, READSTR-l, " %q", v->data+i); while(v->data[i++] != 0){ /* skip */ } if(v->data[i] == 0) break; /* final terminator */ } n = readstr(offset, a, n, p); break; case REG_BINARY: l = n; n = readstr(offset, a, l, "bin"); if(n >= 3){ offset -= 3; if(offset+l > v->size) l = v->size - offset; memmove((char*)a+n, v->data+offset, l); n += l; } break; default: error("unknown registry type"); n=0; break; } poperror(); free(p); c->aux = nil; free(v); break; case Qhostmem: mem.dwLength = sizeof(mem); GlobalMemoryStatus(&mem); /* GlobalMemoryStatusEx isn't on NT */ p = smalloc(READSTR); if(waserror()){ free(p); nexterror(); } snprint(p, READSTR, "load %ld\nphys %lud %lud\nvirt %lud %lud\nswap %lud %lud\n", mem.dwMemoryLoad, mem.dwAvailPhys, mem.dwTotalPhys, mem.dwAvailVirtual, mem.dwTotalVirtual, mem.dwAvailPageFile, mem.dwTotalPageFile); n = readstr(offset, a, n, p); poperror(); free(p); break; default: n=0; break; } return n; } static long archwrite(Chan* c, void* a, long n, vlong offset) { Value *v; int i; Cmdbuf *cb; Rune16 *key, *item; if((ulong)c->qid.path != Qregquery) error(Eperm); USED(offset); if(c->aux != nil){ free(c->aux); c->aux = nil; } cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf < 3) error(Ebadctl); for(i=0; if[0], roots[i].name) == 0) break; if(i >= nelem(roots)) errorf("unknown root: %s", cb->f[0]); key = widen(cb->f[1]); if(waserror()){ free(key); nexterror(); } item = widen(cb->f[2]); if(waserror()){ free(item); nexterror(); } v = getregistry(roots[i].root, key, item); if(v == nil) error(up->env->errstr); c->aux = v; poperror(); free(item); poperror(); free(key); poperror(); free(cb); return n; } Dev archdevtab = { 'a', "arch", archinit, archattach, archwalk, archstat, archopen, devcreate, archclose, archread, devbread, archwrite, devbwrite, devremove, devwstat, }; static void regerr(int rc) { Rune16 err[64]; char emsg[sizeof(err)*UTFmax+1]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, sizeof(err), 0); runes16toutf(emsg, err, nelem(err)); error(emsg); } static Value* getregistry(HKEY root, Rune16 *keyname, Rune16 *name) { long res; HKEY key; DWORD dtype, n; int i, l, nb; void* vp; char *p; Value *val; Rune16 *rb; qlock(®lock); if(waserror()){ qunlock(®lock); return nil; } res = RegOpenKey(root, keyname, &key); if(res != ERROR_SUCCESS) regerr(res); if(waserror()){ RegCloseKey(key); nexterror(); } n = 0; res = RegQueryValueEx(key, name, NULL, &dtype, NULL, &n); if(res != ERROR_SUCCESS) regerr(res); nb = n; if(dtype == REG_SZ || dtype == REG_EXPAND_SZ || dtype == REG_MULTI_SZ){ nb = n*UTFmax + 1; rb = smalloc((n+2)*sizeof(Rune16)); memset(rb, 0, (n+2)*sizeof(Rune16)); }else rb = nil; if(waserror()){ free(rb); nexterror(); } val = smalloc(sizeof(Value)+nb); if(waserror()){ free(val); nexterror(); } val->type = dtype; val->size = n; switch(dtype){ case REG_DWORD: vp = &val->w; break; #ifdef REG_QWORD case REG_QWORD: vp = &val->q; break; #endif case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: vp = rb; break; case REG_BINARY: case REG_NONE: vp = val->data; break; default: errorf("unsupported registry type: %d", dtype); return nil; /* for compiler */ } res = RegQueryValueEx(key, name, NULL, NULL, vp, &n); if(res != ERROR_SUCCESS) regerr(res); poperror(); if(rb != nil){ if(dtype == REG_MULTI_SZ){ p = val->data; for(i=0;;){ l = runes16len(rb+i); runes16toutf(p, rb+i, l); i += l+1; if(rb[i] == 0) break; p += strlen(p)+1; } }else runes16toutf(val->data, rb, n); free(rb); } poperror(); poperror(); RegCloseKey(key); poperror(); qunlock(®lock); return val; }