#include <u.h>
#include <libc.h>
#include <ctype.h>

static int
isme(char *uid)
{
	int n;
	char *p;

	n = strtol(uid, &p, 10);
	if(*p == 0 && p > uid)
		return n == getuid();
	return strcmp(getuser(), uid) == 0;
}
/*
 * Absent other hints, it works reasonably well to use
 * the X11 display name as the name space identifier.
 * This is how sam's B has worked since the early days.
 * Since most programs using name spaces are also using X,
 * this still seems reasonable.  Terminal-only sessions
 * can set $NAMESPACE.
 */
static char*
nsfromdisplay(void)
{
	int fd;
	Dir *d;
	char *disp, *p;

	if((disp = getenv("DISPLAY")) == nil){
#ifdef __APPLE__
		// Might be running native GUI on OS X.
		disp = strdup(":0.0");
		if(disp == nil)
			return nil;
#else
		werrstr("$DISPLAY not set");
		return nil;
#endif
	}

	/* canonicalize: xxx:0.0 => xxx:0 */
	p = strrchr(disp, ':');
	if(p){
		p++;
		while(isdigit((uchar)*p))
			p++;
		if(strcmp(p, ".0") == 0)
			*p = 0;
	}

	/* turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5) */
	for(p=disp; *p; p++)
		if(*p == '/')
			*p = '_';

	p = smprint("/tmp/ns.%s.%s", getuser(), disp);
	free(disp);
	if(p == nil){
		werrstr("out of memory");
		return p;
	}
	if((fd=create(p, OREAD, DMDIR|0700)) >= 0){
		close(fd);
		return p;
	}
	if((d = dirstat(p)) == nil){
		free(d);
		werrstr("stat %s: %r", p);
		free(p);
		return nil;
	}
	if((d->mode&0777) != 0700 || !isme(d->uid)){
		werrstr("bad name space dir %s", p);
		free(p);
		free(d);
		return nil;
	}
	free(d);
	return p;
}

char*
getns(void)
{
	char *ns;

	ns = getenv("NAMESPACE");
	if(ns == nil)
		ns = nsfromdisplay();
	if(ns == nil){
		werrstr("$NAMESPACE not set, %r");
		return nil;
	}
	return ns;
}
