1 /* 2 * platform-specific interface 3 */ 4 5 #define Unknown win_Unknown 6 #define UNICODE 7 #include <windows.h> 8 #include <winbase.h> 9 #include <winsock.h> 10 #undef Unknown 11 #include "dat.h" 12 #include "fns.h" 13 #include "error.h" 14 #include "r16.h" 15 16 enum{ 17 Qdir, 18 Qarchctl, 19 Qcputype, 20 Qregquery, 21 Qhostmem 22 }; 23 24 static 25 Dirtab archtab[]={ 26 ".", {Qdir, 0, QTDIR}, 0, 0555, 27 "archctl", {Qarchctl, 0}, 0, 0444, 28 "cputype", {Qcputype}, 0, 0444, 29 "regquery", {Qregquery}, 0, 0666, 30 "hostmem", {Qhostmem}, 0, 0444, 31 }; 32 33 typedef struct Value Value; 34 struct Value { 35 int type; 36 int size; 37 union { 38 ulong w; 39 vlong q; 40 char data[1]; /* utf-8 */ 41 }; 42 }; 43 44 typedef struct Regroot Regroot; 45 struct Regroot { 46 char* name; 47 HKEY root; 48 }; 49 50 static Regroot roots[] = { 51 {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT}, 52 {"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG}, 53 {"HKEY_CURRENT_USER", HKEY_CURRENT_USER}, 54 {"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE}, 55 {"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA}, 56 {"HKEY_USERS", HKEY_USERS}, 57 }; 58 59 static struct { 60 ulong mhz; 61 int ncpu; 62 char cpu[64]; 63 } arch; 64 65 static QLock reglock; 66 67 static Value* getregistry(HKEY, Rune16*, Rune16*); 68 static int nprocs(void); 69 70 static void 71 archinit(void) 72 { 73 Value *v; 74 char *p; 75 76 v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"ProcessorNameString"); 77 if(v != nil){ 78 snprint(arch.cpu, sizeof(arch.cpu), "%s", v->data); 79 if((p = strrchr(arch.cpu, ' ')) != nil) 80 for(; p >= arch.cpu && *p == ' '; p--) 81 *p = '\0'; 82 free(v); 83 }else{ 84 v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"VendorIdentifier"); 85 if(v != nil){ 86 snprint(arch.cpu, sizeof(arch.cpu), "%s", v->data); 87 free(v); 88 }else 89 snprint(arch.cpu, sizeof(arch.cpu), "unknown"); 90 } 91 v = getregistry(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"~MHz"); 92 if(v != nil){ 93 arch.mhz = v->w; 94 free(v); 95 } 96 arch.ncpu = nprocs(); 97 } 98 99 static int 100 nprocs(void) 101 { 102 int n; 103 char *p; 104 Rune16 *r; 105 Value *v; 106 n = 0; 107 for(;;){ 108 p = smprint("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", n); 109 if(waserror()){ 110 free(p); 111 nexterror(); 112 } 113 r = widen(p); 114 free(p); 115 v = getregistry(HKEY_LOCAL_MACHINE, r, L"~MHz"); 116 free(r); 117 if(v == nil) 118 break; 119 free(v); 120 n++; 121 } 122 return n; 123 } 124 125 static Chan* 126 archattach(char* spec) 127 { 128 return devattach('a', spec); 129 } 130 131 static Walkqid* 132 archwalk(Chan *c, Chan *nc, char **name, int nname) 133 { 134 return devwalk(c, nc, name, nname, archtab, nelem(archtab), devgen); 135 } 136 137 static int 138 archstat(Chan* c, uchar *db, int n) 139 { 140 return devstat(c, db, n, archtab, nelem(archtab), devgen); 141 } 142 143 static Chan* 144 archopen(Chan* c, int omode) 145 { 146 return devopen(c, omode, archtab, nelem(archtab), devgen); 147 } 148 149 static void 150 archclose(Chan* c) 151 { 152 if((ulong)c->qid.path == Qregquery && c->aux != nil) 153 free(c->aux); 154 } 155 156 static long 157 archread(Chan* c, void* a, long n, vlong offset) 158 { 159 char *p; 160 Value *v; 161 int i, l; 162 MEMORYSTATUS mem; 163 164 switch((ulong)c->qid.path){ 165 case Qdir: 166 return devdirread(c, a, n, archtab, nelem(archtab), devgen); 167 case Qarchctl: 168 case Qcputype: 169 l = 0; 170 if((ulong)c->qid.path == Qcputype) 171 l = 4; 172 p = smalloc(READSTR); 173 if(waserror()){ 174 free(p); 175 nexterror(); 176 } 177 snprint(p, READSTR, "cpu %q %lud %d\n", arch.cpu, arch.mhz, arch.ncpu); 178 n = readstr(offset, a, n, p+l); 179 poperror(); 180 free(p); 181 break; 182 case Qregquery: 183 v = c->aux; 184 if(v == nil) 185 return 0; 186 p = smalloc(READSTR); 187 if(waserror()){ 188 free(p); 189 nexterror(); 190 } 191 switch(v->type){ 192 case REG_NONE: 193 n = readstr(offset, a, n, "nil"); 194 break; 195 case REG_DWORD: 196 snprint(p, READSTR, "int %ld", v->w); 197 n = readstr(offset, a, n, p); 198 break; 199 #ifdef REG_QWORD 200 case REG_QWORD: 201 snprint(p, READSTR, "int %lld", v->q); 202 n = readstr(offset, a, n, p); 203 break; 204 #endif 205 case REG_SZ: 206 case REG_EXPAND_SZ: 207 if(v->data[0]) 208 snprint(p, READSTR, "str %q", v->data); 209 n = readstr(offset, a, n, p); 210 break; 211 case REG_MULTI_SZ: 212 l = snprint(p, READSTR, "str"); 213 for(i=0;;){ 214 l += snprint(p+l, READSTR-l, " %q", v->data+i); 215 while(v->data[i++] != 0){ 216 /* skip */ 217 } 218 if(v->data[i] == 0) 219 break; /* final terminator */ 220 } 221 n = readstr(offset, a, n, p); 222 break; 223 case REG_BINARY: 224 l = n; 225 n = readstr(offset, a, l, "bin"); 226 if(n >= 3){ 227 offset -= 3; 228 if(offset+l > v->size) 229 l = v->size - offset; 230 memmove((char*)a+n, v->data+offset, l); 231 n += l; 232 } 233 break; 234 default: 235 error("unknown registry type"); 236 n=0; 237 break; 238 } 239 poperror(); 240 free(p); 241 c->aux = nil; 242 free(v); 243 break; 244 case Qhostmem: 245 mem.dwLength = sizeof(mem); 246 GlobalMemoryStatus(&mem); /* GlobalMemoryStatusEx isn't on NT */ 247 p = smalloc(READSTR); 248 if(waserror()){ 249 free(p); 250 nexterror(); 251 } 252 snprint(p, READSTR, "load %ld\nphys %lud %lud\nvirt %lud %lud\nswap %lud %lud\n", 253 mem.dwMemoryLoad, 254 mem.dwAvailPhys, mem.dwTotalPhys, mem.dwAvailVirtual, mem.dwTotalVirtual, 255 mem.dwAvailPageFile, mem.dwTotalPageFile); 256 n = readstr(offset, a, n, p); 257 poperror(); 258 free(p); 259 break; 260 default: 261 n=0; 262 break; 263 } 264 return n; 265 } 266 267 static long 268 archwrite(Chan* c, void* a, long n, vlong offset) 269 { 270 Value *v; 271 int i; 272 Cmdbuf *cb; 273 Rune16 *key, *item; 274 275 if((ulong)c->qid.path != Qregquery) 276 error(Eperm); 277 USED(offset); 278 if(c->aux != nil){ 279 free(c->aux); 280 c->aux = nil; 281 } 282 cb = parsecmd(a, n); 283 if(waserror()){ 284 free(cb); 285 nexterror(); 286 } 287 if(cb->nf < 3) 288 error(Ebadctl); 289 for(i=0; i<nelem(roots); i++) 290 if(strcmp(cb->f[0], roots[i].name) == 0) 291 break; 292 if(i >= nelem(roots)) 293 errorf("unknown root: %s", cb->f[0]); 294 key = widen(cb->f[1]); 295 if(waserror()){ 296 free(key); 297 nexterror(); 298 } 299 item = widen(cb->f[2]); 300 if(waserror()){ 301 free(item); 302 nexterror(); 303 } 304 v = getregistry(roots[i].root, key, item); 305 if(v == nil) 306 error(up->env->errstr); 307 c->aux = v; 308 poperror(); 309 free(item); 310 poperror(); 311 free(key); 312 poperror(); 313 free(cb); 314 return n; 315 } 316 317 Dev archdevtab = { 318 'a', 319 "arch", 320 321 archinit, 322 archattach, 323 archwalk, 324 archstat, 325 archopen, 326 devcreate, 327 archclose, 328 archread, 329 devbread, 330 archwrite, 331 devbwrite, 332 devremove, 333 devwstat, 334 }; 335 336 static void 337 regerr(int rc) 338 { 339 Rune16 err[64]; 340 char emsg[sizeof(err)*UTFmax+1]; 341 342 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 343 0, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 344 err, sizeof(err), 0); 345 runes16toutf(emsg, err, nelem(err)); 346 error(emsg); 347 } 348 349 static Value* 350 getregistry(HKEY root, Rune16 *keyname, Rune16 *name) 351 { 352 long res; 353 HKEY key; 354 DWORD dtype, n; 355 int i, l, nb; 356 void* vp; 357 char *p; 358 Value *val; 359 Rune16 *rb; 360 361 qlock(®lock); 362 if(waserror()){ 363 qunlock(®lock); 364 return nil; 365 } 366 res = RegOpenKey(root, keyname, &key); 367 if(res != ERROR_SUCCESS) 368 regerr(res); 369 if(waserror()){ 370 RegCloseKey(key); 371 nexterror(); 372 } 373 n = 0; 374 res = RegQueryValueEx(key, name, NULL, &dtype, NULL, &n); 375 if(res != ERROR_SUCCESS) 376 regerr(res); 377 nb = n; 378 if(dtype == REG_SZ || dtype == REG_EXPAND_SZ || dtype == REG_MULTI_SZ){ 379 nb = n*UTFmax + 1; 380 rb = smalloc((n+2)*sizeof(Rune16)); 381 memset(rb, 0, (n+2)*sizeof(Rune16)); 382 }else 383 rb = nil; 384 if(waserror()){ 385 free(rb); 386 nexterror(); 387 } 388 val = smalloc(sizeof(Value)+nb); 389 if(waserror()){ 390 free(val); 391 nexterror(); 392 } 393 val->type = dtype; 394 val->size = n; 395 switch(dtype){ 396 case REG_DWORD: 397 vp = &val->w; 398 break; 399 #ifdef REG_QWORD 400 case REG_QWORD: 401 vp = &val->q; 402 break; 403 #endif 404 case REG_SZ: 405 case REG_EXPAND_SZ: 406 case REG_MULTI_SZ: 407 vp = rb; 408 break; 409 case REG_BINARY: 410 case REG_NONE: 411 vp = val->data; 412 break; 413 default: 414 errorf("unsupported registry type: %d", dtype); 415 return nil; /* for compiler */ 416 } 417 res = RegQueryValueEx(key, name, NULL, NULL, vp, &n); 418 if(res != ERROR_SUCCESS) 419 regerr(res); 420 poperror(); 421 if(rb != nil){ 422 if(dtype == REG_MULTI_SZ){ 423 p = val->data; 424 for(i=0;;){ 425 l = runes16len(rb+i); 426 runes16toutf(p, rb+i, l); 427 i += l+1; 428 if(rb[i] == 0) 429 break; 430 p += strlen(p)+1; 431 } 432 }else 433 runes16toutf(val->data, rb, n); 434 free(rb); 435 } 436 poperror(); 437 poperror(); 438 RegCloseKey(key); 439 poperror(); 440 qunlock(®lock); 441 return val; 442 } 443