#include <9pm/windows.h> #include <9pm/u.h> #include <9pm/libc.h> #include "syscall.h" static long _passfd(int, HANDLE); static void _initenv(void); static Rune srv[] = L"Plan 9 Kernel"; static int fdid[3] = { STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE }; static HANDLE hsrv; static HWND hwin; static ulong _tlssyscall; Syscallmem* _getsyscallmem(void) { return TlsGetValue(_tlssyscall); } static void console(void *a) { int *fd, i; char *arg[10]; char buf[3][20]; fd = a; arg[0] = "console"; arg[1] = "--"; for(i=0; i<3; i++){ close(fd[2*i+1]); sprint(buf[i], "%d", fd[2*i]); arg[2+i] = buf[i]; } arg[5] = nil; sprint(buf[0], "%d", fd[0]); sprint(buf[1], "%d", fd[2]); sprint(buf[2], "%d", fd[4]); exec("/9pm/bin/aux/console", arg); } void pm_syscallinit(void) { char *what, err[ERRMAX], buf[256]; int needconsole, fd[6], i, pid, p[2]; DWORD m; HANDLE std, hh; _tlssyscall = TlsAlloc(); if(_tlssyscall == TLS_OUT_OF_INDEXES){ what = "TlsAlloc"; Err: osrerrstr(err, sizeof err); snprint(buf, sizeof buf, "syscallinit: %s: %s", what, err); hh = GetStdHandle(STD_ERROR_HANDLE); WriteFile(hh, buf, strlen(buf), &m, nil); ExitProcess(1); } hwin = FindWindow(srv, srv); if(hwin == 0){ what = "FindWindow"; goto Err; } if(!GetWindowThreadProcessId(hwin, &pid)){ what = "GetWindowThreadProcessId"; goto Err; } hsrv = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); if(hsrv == nil){ what = "OpenProcess"; goto Err; } _syscallinit(_plan9id); if(_plan9id==0){ /* are starting from scratch; initialize state */ needconsole = 0; for(i=0; i<3; i++){ fd[2*i] = fd[2*i+1] = -1; std = GetStdHandle(fdid[i]); if(std==nil || std==INVALID_HANDLE_VALUE) continue; if(_passfd(i, std) < 0){ pipe(fd+2*i); needconsole = 1; } _initenv(); if(needconsole){ ffork(RFNOWAIT|RFFDG, console, fd, 8192); close(fd[0]); close(fd[2]); close(fd[4]); } for(i=0; i<3; i++){ if(fd[2*i+1] != i && fd[2*i+1] >= 0){ dup(fd[2*i+1], i); close(fd[2*i+1]); } } } } void _syscallinit(int pid) { char *what, err[ERRMAX], buf[256]; DWORD m; HANDLE hh, hmem; Syscallmem *c; hmem = (void*)SendMessage(hwin, WM_USER, pid, GetCurrentProcessId()); if(hmem == nil){ what = "SendMessage"; Err: osrerrstr(err, sizeof err); snprint(buf, sizeof buf, "syscallinit: %s: %s", what, err); hh = GetStdHandle(STD_ERROR_HANDLE); WriteFile(hh, buf, strlen(buf), &m, nil); ExitProcess(1); } if(hmem==(HANDLE)1){ pm_dprint(~0, "Could not attach to kernel as process %d\n", pid); ExitProcess(1); } c = MapViewOfFile(hmem, FILE_MAP_WRITE, 0, 0, 0); if(c == nil){ what = "MapViewOfFile"; goto Err; } TlsSetValue(_tlssyscall, c); } long _dosyscall(Syscallmem *c) { char status; Rune *p, *q; int ret; if(!ReleaseSemaphore(c->hc.hserversig, 1, nil)) abort(); if(WaitForSingleObject(c->hc.hclientsig, INFINITE) != WAIT_OBJECT_0) abort(); /* BUG: check for notify */ switch(c->state){ case Exit: CloseHandle(c->hc.hserversig); CloseHandle(c->hc.hclientsig); CloseHandle(c->hc.hmem); CloseHandle(c->hc.hkillsig); status = c->exitstatus[0]; UnmapViewOfFile(c); ExitThread(status); /* * Exec leaves the command name and command line for us; * we prepare to execute, do Sexec once more to commit, * and drop our handles, run CreateProcess, and ExitThread. */ case Exec: p = (Rune*)&c[1]; q = p+runestrlen(p)+1; p = runestrcpy(p); q = runestrcpy(q); if(p==nil || q==nil){ free(p); free(q); werrstr("out of memory"); return -1; } c->nr = Sexec; ReleaseSemaphore(c->hc.hserversig, 1, nil); CloseHandle(c->hc.hserversig); CloseHandle(c->hc.hclientsig); CloseHandle(c->hc.hmem); CloseHandle(c->hc.hkillsig); UnmapViewOfFile(c); CreateProcess(p, q, nil, nil, 0, nil, nil, nil, nil); ExitThread(0); } return c->ret; } static char* wenv2env(Rune *r) { char *s; Rune *rr; int len, n; len = 0; for(rr=r; *rr; rr+=runestrlen(rr)+1) len += runenlen(rr, runestrlen(rr))+1; len += 10; s = malloc(len); if(s == nil) return nil; n = 0; for(rr=r; *rr; rr+=runestrlen(rr)+1){ win_wstr2utfn(s+n, len-n, rr); pm_dprint(PmDebugNs, "'%s'\n", s+n); n += strlen(s+n)+1; } return s; } static void _initenv(void) { char buf[256]; int fd; Rune *wenv; char *env, *p, *q; wenv = GetEnvironmentStrings(); if(wenv == nil) return; env = wenv2env(wenv); FreeEnvironmentStrings(wenv); if(env == nil) return; for(p=env; *p; p+=strlen(p)+1){ q = strchr(p+1, '='); if(q == nil) continue; *q++ = '\0'; if(strlen(p) > 250) continue; snprint(buf, sizeof buf, "#e/%s", p); if((fd = create(buf, OWRITE, 0666)) < 0) continue; write(fd, q, strlen(q)); close(fd); } } /* * Could do this with a '#H' equivalent to #d. */ static long _passfd(int fd, HANDLE h) { Syscallmem *c; c = _getsyscallmem(); c->arg[0] = fd; c->arg[1] = (ulong)h; c->nr = Spassfd; return _dosyscall(c); }