Plan 9 from Bell Labs’s /usr/web/sources/patch/maybe/rc-win32/win32.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * Plan 9 versions of system-specific functions
 *	By convention, exported routines herein have names beginning with an
 *	upper case letter.
 */
#include <windows.h>
#include <stdio.h>
#include <string.h>
#undef IN
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
#include "getflags.h"

enum {
	Maxshebang = 1024
};

struct {
	int e;
	char *s;
} Winerrs[] = {				/* some more common errors translated to more friendly messages */
	{ ERROR_HANDLE_EOF,				"end of file" },
	{ ERROR_INVALID_HANDLE,			"invalid handle" },
	{ ERROR_SHARING_VIOLATION,		"sharing violation" },
	{ ERROR_FILE_NOT_FOUND,			"file does not exist" },
	{ ERROR_PATH_NOT_FOUND,			"path does not exist" },
	{ ERROR_BAD_PATHNAME,			"bad path" },
	{ ERROR_TOO_MANY_OPEN_FILES,	"too many open files" },
	{ ERROR_ACCESS_DENIED,			"permission denied" },
	{ ERROR_INVALID_NAME,			"filename syntax" },
	{ ERROR_OUTOFMEMORY,			"out of memory" },
	{ ERROR_NOT_ENOUGH_MEMORY,		"not enough emmory" },
	{ ERROR_WRITE_PROTECT,			"read only" },
	{ ERROR_BROKEN_PIPE,			"broken pipe" },
	{ ERROR_NO_MORE_SEARCH_HANDLES,	"too many open directories" },
	{ ERROR_ALREADY_EXISTS,			"already exists" },
	{ ERROR_BAD_EXE_FORMAT,			"bad executable format" },
	{ ERROR_SEEK_ON_DEVICE,			"seek on device" },
	{ ERROR_GEN_FAILURE,			"general failure" },
	{ ERROR_NOT_SUPPORTED,			"not supported" },
	{ ERROR_NOT_READY,				"device not ready" },
	{ ERROR_BAD_NETPATH,			"network path not found" },
	{ ERROR_BAD_NET_NAME,			"host not known" },
	{ ERROR_HANDLE_DISK_FULL,		"disk full" },
	{ 0,							nil },
};

char *Signame[] = {
	"sigexit",	"sighup",	"sigint",	"sigquit",
	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
	0
};

char *Rcmain = "undefined";


void execfinit(void);

builtin Builtin[] = {
	"cd",		execcd,
	"whatis",	execwhatis,
	"eval",		execeval,
	"exec",		execexec,	/* but with popword first */
	"exit",		execexit,
	"shift",	execshift,
	"wait",		execwait,
	".",		execdot,
	"finit",	execfinit,
	"flag",		execflag,
	0
};

#define	SEP	';'
char *xenviron;

/*
 * Windows preserves case but ignores it, even in environment variables.
 * We need to be able to find these vars so we force their
 * case to that below as they are parsed from the environment.
 */
char *Force[] = {
	"path",
	"pathext",
	nil
};


static struct {
	int pid;
	HANDLE hand;
} Child[10];


static int
cistrcmp(char *s1, char *s2)
{
	int c1, c2;

	while(*s1){
		c1 = *(uchar*)s1++;
		c2 = *(uchar*)s2++;

		if(c1 == c2)
			continue;

		if(c1 >= 'A' && c1 <= 'Z')
			c1 -= 'A' - 'a';

		if(c2 >= 'A' && c2 <= 'Z')
			c2 -= 'A' - 'a';

		if(c1 != c2)
			return c1 - c2;
	}
	return -*s2;
}

struct word*
enval(char *s)
{
	char *t, c;
	struct word *v;

	for(t = s;*t && *t != SEP;t++)
		continue;

	c=*t;
	*t='\0';
	v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
	*t = c;
	return v;
}

static void
reslash(char *s, char new)
{
	char *p;

	for(p = s; *p; p++)
		if(*p == '\\' || *p == '/')
			*p = new;
}

int
cmpvar(const void *aa, const void *ab)
{
	struct var * const *a = aa, * const *b = ab;

	return strcmp((*a)->name, (*b)->name);
}

char *
exportenv(void)
{
	char *env, *p, *q;
	struct var **h, *v, **idx;
	struct word *a;
	int nvar = 0, nchr = 0, sep, i;
int x;
	/*
	 * Slightly kludgy loops look at locals then globals.
	 * locals no longer exist - geoff
	 */
	for(h = gvar-1; h != &gvar[NVAR]; h++)
	for(v = h >= gvar? *h: runq->local; v ;v = v->next){
		if(v==vlook(v->name) && v->val){
			nvar++;
			nchr+=strlen(v->name)+1;
			for(a = v->val;a;a = a->next)
				nchr+=strlen(a->word)+1;
		}
		if(v->fn){
			nvar++;
			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
		}
	}

	idx = (struct var **)emalloc(nvar * sizeof(struct var *));

	i = 0;
	for(h = gvar-1; h != &gvar[NVAR]; h++)
	for(v = h >= gvar? *h: runq->local; v ;v = v->next){
		if((v==vlook(v->name) && v->val) || v->fn)
			idx[i++] = v;
	}

	qsort((void *)idx, nvar, sizeof idx[0], cmpvar);

	env = (char *)emalloc(nvar+nchr+1);

	p = env;
	for(i = 0; i < nvar; i++){
		v = idx[i];
		if((v==vlook(v->name)) && v->val){
			q = v->name;
			while(*q) *p++=*q++;
			sep='=';
			for(a = v->val;a;a = a->next){
				*p++=sep;
				sep = SEP;
				q = a->word;
				while(*q) *p++=*q++;
			}
			*p++='\0';
		}
		if(v->fn){
			*p++='f'; *p++='n'; *p++='#';
			q = v->name;
			while(*q) *p++=*q++;
			*p++='=';
			q = v->fn[v->pc-1].s;
			while(*q) *p++=*q++;
			*p++='\0';
		}
	}
	*p = 0;

	return env;	
}
	
/*
 * had to change the parsing from plan9/unix code as windows
 * tends to use braces in variables and variable names with inpunity.
 * FIXME: should handle UTF really
 */
void
Vinit(void)
{
	int a;
	struct word *w;
	char *p, *s, **f, *env;
	static char buf[MAX_PATH];

	env = GetEnvironmentStrings();
	xenviron = env;
	for(; env && *env; env = strchr(env, 0)+1){
		if((s = strchr(env, '=')) == NULL)
			continue;
		if(strncmp(env, "fn#", 3) == 0)		/* ignore functions */
			continue;
		*s='\0';
		for(f = Force; *f; f++)
			if(cistrcmp(*f, env) == 0)
				break;
		if(*f){
			reslash(s+1, '/');
			setvar(*f, enval(s+1));
		}else{
			setvar(env, enval(s+1));
		}
		*s='=';
	}

	/* look for rcmain in $path */
	for(w = vlook("path")->val; w; w = w->next){
		snprintf(buf, sizeof(buf), "%s/rcmain", w->word);
		a = GetFileAttributes(buf);
		if(a != -1 && a != FILE_ATTRIBUTE_DIRECTORY)
			break;
	}
	if(w == nil){
		pfmt(err, "rc: cannot find 'rcmain' in $path :\n");
		exit(0);
	}
	Rcmain = buf;
}

char *xenv;

/*
 * called once per func read from env, returns after each,
 * but calls Xreturn() before returning when the list is empty
 */
void
Xrdfn(void)
{
	int len;
	char *s, *nxt;

	for(; xenv && *xenv; xenv = nxt){
		nxt = strchr(xenv, 0) +1;
		if(strncmp(xenv, "fn#", 3) != 0)		/* ignore variables */
			continue;
		if((s = strchr(xenv, '=')) == NULL)
			continue;

		len = strlen(xenv);
		*s=' ';
		xenv[2]=' ';
		xenv[len]='\n';
		execcmds(opencore(xenv, len+1));
		xenv[len]='\0';
		xenv[2]='#';
		*s='=';
		xenv = nxt;
		return;
	}
	Xreturn();
}


union code rdfns[4];

void
execfinit(void)
{
	static int first = 1;
	if(first){
		rdfns[0].i = 1;
		rdfns[1].f = Xrdfn;
		rdfns[2].f = Xjump;
		rdfns[3].i = 1;
		first = 0;
	}
	Xpopm();
	xenv = xenviron;
	start(rdfns, 1, runq->local);
}

static int
addchild(int pid, HANDLE hand)
{
	int i;
	
	for(i = 0; i < nelem(Child); i++) {
		if(Child[i].hand == 0) {
			Child[i].pid = pid;
			Child[i].hand = hand;
			return 1;
		}
	}
	pfmt(err, "adchild: child table full\n");
	return 0;
}

/* NB: return -1 only on interrupt, may cause a retry */
int
Waitfor(int pid, int persist)
{
	int i;
	HANDLE h;
	ulong status;
	char buf[32];

	if(pid == 0)
		return 0;

	for(i = 0; i < nelem(Child); i++)
		if(Child[i].pid == pid){
			h = Child[i].hand;
			break;
		}

	/* we don't know about this one - let the system try to find it */
	if(h == nil){
		h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
		if(h == nil){
			pfmt(err, "%d cannot open process\n", pid);
			return 0;
		}
	}

	status = 1;
	WaitForSingleObject(h, INFINITE);
	GetExitCodeProcess(h, &status);

	CloseHandle(h);
	for(i = 0; i < nelem(Child); i++)
		if(Child[i].pid == pid){
			Child[i].pid = 0;
			Child[i].hand = nil;
			break;
		}

	if(status){
		inttoascii(buf, status);
		setstatus(buf);
		return 0;
	}
	setstatus("");
	return 0;
}

void
Updenv(void)
{
}

void
Execute(word *args, word *path)
{
	pfmt(err, "rc: exec not supported\n");
}

int
Abspath(char *w)
{
	if(strncmp(w, "./", 2)==0)
		return 1;
	if(strncmp(w, ".\\", 2)==0)
		return 1;
	if(strncmp(w, "../", 3)==0)
		return 1;
	if(strncmp(w, "..\\", 3)==0)
		return 1;
	if(strncmp(w, "/", 1)==0)
		return 1;
	if(strncmp(w, "\\", 1)==0)
		return 1;
	if(isalpha(w[0]) && w[1] == ':') 
		return 1;
	return 0;
}

int
Globsize(char *p)
{
	int isglob, globlen;

	isglob = 0;
	globlen = FILENAME_MAX+1;

	for(; *p; p++){
		if(*p == GLOB){
			p++;
			if(*p != GLOB)
				isglob++;
			if(*p == '*')
				globlen += FILENAME_MAX;
			else
				globlen += 1;
		}
		else
			globlen++;
	}
	if(isglob)
		return globlen;
	return 0;
}


enum { Ndirs = 50 };
typedef struct {
	HANDLE h;
	int first;
	WIN32_FIND_DATA data;
} Dir;
static Dir Dirs[Ndirs];

int
Opendir(char *path)
{
	long n;
	Dir *dp;
	char fullpath[MAX_PATH];


	for(dp = Dirs; dp < &Dirs[Ndirs]; dp++)
		if(dp == nil){
			snprintf(fullpath, MAX_PATH, "%s\\*.*", path);
			dp->h = FindFirstFile(fullpath, &dp->data);
			if(dp->h == INVALID_HANDLE_VALUE){
				dp->h = 0;						/* paranoia */
				return -1;
			}
			dp->first = 1;
			return dp-Dirs;
		}
	return -1;
}

static int
validfile(WIN32_FIND_DATA *wfd, int onlydirs)
{
	char *s;

	s = wfd->cFileName;
	if(! (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && onlydirs)
		return 0;
	if(s[0] == '.' && s[1] == 0)
		return 0;
	if(s[0] == '.' && s[1] == '.' && s[2] == 0)
		return 0;
	return 1;
}

/*
 * onlydirs is advisory -- it means you only
 * need to return the directories.  it's okay to
 * return files too (e.g., on unix where you can't
 * tell during the readdir), but that just makes 
 * the globber work harder.
 */
int
Readdir(int f, void *p, int onlydirs)
{
	int n;
	WIN32_FIND_DATA *wfd;

	if(f < 0 || f >= Ndirs)
		return -1;

	wfd = &Dirs[f].data;
	if(Dirs[f].first){
		Dirs[f].first = 0;
		if(validfile(wfd, onlydirs)){
			strcpy(p, wfd->cFileName);
			return 1;
		}
	}

	while(FindNextFile(Dirs[f].h, wfd) != 0){
		if(! validfile(wfd, onlydirs))
			continue;
		strcpy(p, wfd->cFileName);
		return 1;
	}
	return 0;
}

void
Closedir(int f)
{
	if(f < 0 || f >= Ndirs)
		return;

	FindClose(Dirs[f].h);
	Dirs[f].h = 0;
}

int interrupted = 0;

static BOOL WINAPI
gettrap(DWORD code)
{
	int i;

	switch(code){
	case CTRL_C_EVENT:
		trap[SIGINT]++;
		break;
	case CTRL_BREAK_EVENT:
		trap[SIGQUIT]++;
		break;
	case CTRL_CLOSE_EVENT:	/* window close or "End Task"  task manager */
	case CTRL_LOGOFF_EVENT:
	case CTRL_SHUTDOWN_EVENT:
		trap[SIGTERM]++;
		break;
	default:
		pfmt(err, "rc: %d unexpected trap code\n", code);
		break;
	}
	ntrap++;
	if(ntrap >= NSIG){
		pfmt(err, "rc: Too many traps (trap %d), aborting\n", code);
		return 0;		/* default action (exit) */
	}
	
	interrupted = 1;
	for(i = 0; i < nelem(Child); i++)
		if(Child[i].hand != nil)
			GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, Child[i].pid);
	return 1;			/* continue */
}

void
Trapinit(void)
{
	SetConsoleCtrlHandler(gettrap, TRUE);
}

void
Unlink(char *name)
{
	remove(name);
}

long
Write(int fd, void *buf, long cnt)
{
	return write(fd, buf, cnt);
}

long
Read(int fd, void *buf, long cnt)
{
	int n;

	n = read(fd, buf, cnt);
	if(interrupted)
		return -1;
	return n;
}

long
Seek(int fd, long cnt, long whence)
{
	return lseek(fd, cnt, whence);
}


/* used by whatis only */
int
Executable(char *file)
{
	int a;
	FILE *fp;
	ulong type;
	struct word *w;
	char *ext, buf[4];

	if(GetBinaryType(file, &type))
		return 1;

	if((ext = strrchr(file, '.')) != nil)
		for(w = vlook("pathext")->val; w; w = w->next)
			if(cistrcmp(ext, w->word) == 0)
				return 1;

	if((fp = fopen(file, "r")) == nil)
		return 0;
	if(fread(buf, 1, sizeof(buf), fp) <= 0){
		fclose(fp);
		return 0;
	}
	fclose(fp);
	if(strncmp(buf, "#!", 2) == 0)
		return 1;
	return 0;
}

int
Creat(char *file)
{
	return creat(file, 0644);
}

int
Dup(int a, int b)
{
	return dup2(a, b);
}

int
Dup1(int a)
{
	return dup(a);
}

void
Exit(char *stat)
{
	int n = 0;

	while(*stat){
		if(*stat != '|'){
			if(*stat < '0' || '9' < *stat)
				exit(1);
			else n = n*10 + *stat - '0';
		}
		stat++;
	}
	exit(n);
}

int
Eintr(void)
{
	return interrupted;
}

void
Noerror(void)
{
	interrupted = 0;
}
 
int
Isatty(int fd)
{
	switch(GetFileType((HANDLE *)_get_osfhandle(fd))){
	case FILE_TYPE_CHAR:	/* console or maybe a uart */
	case FILE_TYPE_PIPE:	/* ssh session */
		return 1;
	case FILE_TYPE_DISK:	/* redirection */
	case FILE_TYPE_REMOTE:	/* unused they say */
	case FILE_TYPE_UNKNOWN:
	default:
		return 0;
	}
}

void
Abort(void)
{
	pfmt(err, "aborting\n");
	flush(err);
	exit(2);
}

void
Memcpy(void *a, void *b, long n)
{
	memmove(a, b, n);
}

void*
Malloc(ulong n)
{
	return malloc(n);
}

int
needsrcquote(int c)
{
	if(c <= ' ')
		return 1;
	if(strchr("`^#*[]=|\\?${}()'<>&;", c))
		return 1;
	return 0;
}

void
errstr(char *buf, int len)
{
	int e, i;
	char *p, *q;

	e = GetLastError();
	if(e == ERROR_SUCCESS){
		*buf = 0;
		return;
	}

	for(i = 0; Winerrs[i].e; i++)
		if(Winerrs[i].e == e){
			strncpy(buf, Winerrs[i].s, len);
			buf[len -1] = 0;
			return;
		}

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, e, 0, buf, len, 0);
	for(p=q=buf; *p; p++) {
		if(*p == '\r')
			continue;
		if(*p == '\n')
			*q++ = ' ';
		else
			*q++ = *p;
	}
}

char **
mkargv(struct word *a)
{
	int n;
	char **argv, **argp;

	n = count(a)+2;
	if(n < 8)			/* plenty of room for shebangs */
		n = 8;
	argv = (char **)emalloc(n*sizeof(char *));
	memset(argv, 0, n*sizeof(char *));


	argp = argv+1;	/* leave one at front for runcoms */
	for(;a;a = a->next)
		*argp++=a->word;
	*argp = 0;
	return argv;
}

static int
setpath(char *path, char *file)
{
	char *p, *last, tmp[MAX_PATH+1];
	int n;

	if(strlen(file) >= MAX_PATH){
		pfmt(err, "%s: file name too long", file);
		return -1;
	}
	strcpy(tmp, file);

	for(p=tmp; *p; p++) {
		if(*p == '/')
			*p = '\\';
	}

	if(tmp[0] != 0 && tmp[1] == ':') {
		if(tmp[2] == 0) {
			tmp[2] = '\\';
			tmp[3] = 0;
		} else if(tmp[2] != '\\') {
			/* don't allow c:foo - only c:\foo */
			pfmt(err, "%s: illegal file name", file);
			return -1;
		}
	}

	path[0] = 0;
	n = GetFullPathName(tmp, MAX_PATH, path, &last);
	if(n >= MAX_PATH) {
		pfmt(err, "%s: expanded path too long", file);
		return -1;
	}
	if(n == 0 && tmp[0] == '\\' && tmp[1] == '\\' && tmp[2] != 0) {
		strcpy(path, tmp);
		return -1;
	}

	if(n == 0) {
		pfmt(err, "%s: bad file name", tmp);
		return -1;
	}

	for(p=path; *p; p++) {
		if(*p < 32 || *p == '*' || *p == '?') {
			pfmt(err, "%s: wildcards in path", path);
			return -1;
		}
	}

	/* get rid of trailling \ */
	if(path[n-1] == '\\') {
		if(n <= 2) {
			pfmt(err, "%s: illegal path", path);
			return -1;
		}
		path[n-1] = 0;
		n--;
	}

	if(path[1] == ':' && path[2] == 0) {
		path[2] = '\\';
		path[3] = '.';
		path[4] = 0;
		return -1;
	}

	if(path[0] != '\\' || path[1] != '\\')
		return 0;

	for(p=path+2,n=0; *p; p++)
		if(*p == '\\')
			n++;
	if(n == 0)
		return -1;
	if(n == 1)
		return -1;
	return 0;
}

static int
shargs(char *s, int n, char **ap)
{
	int i;

	s += 2;
	n -= 2;		/* skip #! */
	for(i=0; s[i]!='\n'; i++)
		if(i == n-1)
			return 0;
	s[i] = 0;

	if(flag['p'])
		pfmt(err, "got %s\n", s);

	*ap = 0;
	i = 0;
	for(;;) {
		while(*s==' ' || *s=='\t')
			s++;
		if(*s == 0)
			break;
		i++;
		*ap++ = s;
		*ap = 0;
		while(*s && *s!=' ' && *s!='\t')
			s++;
		if(*s == 0)
			break;
		else
			*s++ = 0;
	}
	return i;
}

static int
exetype(char *path, char *file, char **bangv)
{
	int a, n, hasext;
	FILE *fp;
	ulong type;
	struct word *w;
	char *ext, *p;
	static char line[Maxshebang];

	/* has it a valid looking extension? */
	hasext = 0;
	if((ext = strrchr(file, '.')) != 0){
		for(w = vlook("pathext")->val; w; w = w->next)
			if(cistrcmp(ext, w->word) == 0){
				hasext++;
				snprintf(path, MAX_PATH, "%s", file);
				if(flag['p'])
					pfmt(err, "srch: %s good ext\n", path);
				a = GetFileAttributes(path);
				if(a != -1 && a != FILE_ATTRIBUTE_DIRECTORY)
					return 0;
			}
	}

	/* is it an rc script, or a windows executable? */
	snprintf(path, MAX_PATH, "%s", file);
	if(flag['p'])
		pfmt(err, "srch: %s raw name\n", path);
	if((fp = fopen(path, "r")) != nil)
		if((n = fread(line, 1, sizeof(line), fp)) > 0){
			fclose(fp);

			if(strncmp(line, "MZ", 2) == 0)
				return 0;

			if(strncmp(line, "#!", 2) == 0)
				if(shargs(line, n, bangv) > 0){
					if(strcmp(bangv[0], "/bin/rc") == 0)
						bangv[0] = argv0;
					snprintf(path, MAX_PATH, "%s", bangv[0]);
					return 0;
				}
	}

	/* try appending a known extensions (.BAT files etc)*/
	if(! hasext)
		for(w = vlook("pathext")->val; w; w = w->next){
			snprintf(path, MAX_PATH, "%s%s", file, w->word);
			if(flag['p'])
				pfmt(err, "srch: %s add ext\n", path);
			a = GetFileAttributes(path);
			if(a != -1 && a != FILE_ATTRIBUTE_DIRECTORY)
				return 0;
		}
	return -1;
}



/*
 * windows quoting rules - I think
 * Words are seperated by space or tab
 * Words containing a space or tab can be quoted using "
 * 2N backslashes + " ==> N backslashes and end quote
 * 2N+1 backslashes + " ==> N backslashes + literal "
 * N backslashes not followed by " ==> N backslashes
 */
static char *
dblquote(char *cmd, char *s)
{
	int nb;
	char *p;

	for(p=s; *p; p++)
		if(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '"')
			break;

	if(p == s){					/* empty arg */
		strcpy(cmd, "\"\"");
		return cmd+2;
	}

	if(*p == 0){				/* easy case */
		strcpy(cmd, s);
		return cmd+(p-s);
	}

	*cmd++ = '"';
	for(;;) {
		for(nb=0; *s=='\\'; nb++)
			*cmd++ = *s++;

		if(*s == 0) {			/* trailing backslashes -> 2N */
			while(nb-- > 0)
				*cmd++ = '\\';
			break;
		}

		if(*s == '"') {			/* literal quote -> 2N+1 backslashes */
			while(nb-- > 0)
				*cmd++ = '\\';
			*cmd++ = '\\';		/* escape the quote */
		}
		*cmd++ = *s++;
	}

	*cmd++ = '"';
	*cmd = 0;

	return cmd;
}

static char *
proccmd(char **bangv, char **argv)
{
	int i, n;
	char *cmd, *p;

	/* conservatively calculate length of command;
	 * backslash expansion can cause growth in dblquote().
	 */
	n = 0;
	for(i=0; bangv[i]; i++)
		n += (bangv[i])? 2*strlen(bangv[i]): 2;
	for(i=0; argv[i]; i++)
		n += (argv[i])? 2*strlen(argv[i]): 2;
	n++;
	
	cmd = emalloc(n);
	p = cmd;
	for(i=0; bangv[i]; i++){
		p = dblquote(p, bangv[i]);
		*p++ = ' ';
	}
	for(i=0; argv[i]; i++){
		p = dblquote(p, argv[i]);
		*p++ = ' ';
	}
	if(p != cmd)
		p--;
	*p = 0;

	return cmd;
}

int
pipe(int *fd)
{
	/*
	 * If you want binary pipes in to/out of
	 * rc then you will probably want to change
	 * the definition of ifs in rcmain to include
	 * a carriage return. I cannot see why you would
	 * want to do this, but perhaps its a lack of vision.
	 * -Steve
	 */
	return _pipe(fd, 8192, _O_TEXT);
}

static HANDLE
fdexport(int fd)
{
	HANDLE h, r;

	if(fd < 0)
		return INVALID_HANDLE_VALUE;

	h = (HANDLE)_get_osfhandle(fd);
	if(h < 0)
		return INVALID_HANDLE_VALUE;

	if(!DuplicateHandle(GetCurrentProcess(), h,
				GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS,
				1, DUPLICATE_SAME_ACCESS))
		return INVALID_HANDLE_VALUE;
	return r;
}

int
ForkExecute(char *name, char **argv, int sin, int sout, int serr)
{
	int r;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	char path[MAX_PATH], *bangv[1024], *cmd, *env;

	bangv[0] = 0;
	if(exetype(path, name, bangv) == -1)
		return -1;

	memset(&si, 0, sizeof(si));
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_SHOW;
	si.hStdInput = fdexport(sin);
	si.hStdOutput = fdexport(sout);
	si.hStdError = fdexport(serr);

	env = exportenv();
	cmd = proccmd(bangv, argv);

	if(flag['d'])
		pfmt(err, "proc: path='%s' cmd='%s'\n", path, cmd);
	r = CreateProcess(path, cmd, nil, nil, TRUE, CREATE_NEW_PROCESS_GROUP, env, nil, &si, &pi);

	/* allow child to run */
	Sleep(0);

	free(cmd);
	free(env);

	CloseHandle(si.hStdInput);
	CloseHandle(si.hStdOutput);
	CloseHandle(si.hStdError);

	if(!r){
		setstatus("cannot create process");
		return 0;
	}

	CloseHandle(pi.hThread);
	if(addchild(pi.dwProcessId, pi.hProcess) == 0)
		return 0;

	return pi.dwProcessId;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].