#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);
}
syntax highlighted by Code2HTML, v. 0.9.1