/*
 * This file is part of the UCB release of Plan 9. It is subject to the license
 * terms in the LICENSE file found in the top-level directory of this
 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
 * part of the UCB release of Plan 9, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms contained
 * in the LICENSE file.
 */

#include <u.h>
#include <lib9.h>
#include <bio.h>
#include <auth.h>
#include <9P2000.h>

#pragma	varargck	type	"P"	char*

int	nsrv;
Dir	*srv;
Biobuf	stdout;

typedef struct Mount Mount;

struct Mount
{
	char	*cmd;
	char	*flag;
	char	*new;
	char	*old;
	char	*spec;
};

void	xlatemnt(Mount*);
char	*quote(char*);

int	rflag;

void
usage(void)
{
	fprint(2, "usage: ns/cat [-r] [pid]\n");
	exits("usage");
}

void
main(int argc, char **argv)
{
	Mount *m;
	int line, fd, n, pid;
	char buf[1024], *av[5];

	ARGBEGIN{
	case 'r':
		rflag++;
		break;
	default:
		usage();
	}ARGEND

	if(argc > 1)
		usage();
	if(argc == 1){
		pid = atoi(argv[0]);
		if(pid == 0)
			usage();
	}else
		pid = getpid();

	Binit(&stdout, 1, OWRITE);

	sprint(buf, "/proc/%d/ns", pid);
	fd = open(buf, OREAD);
	if(fd < 0) {
		fprint(2, "ns: open %s: %r\n", buf);
		exits("open ns");
	}

	for(line=1; ; line++) {
		n = read(fd, buf, sizeof(buf));
		if(n == sizeof(buf)) {
			fprint(2, "ns: ns string too int32_t\n");
			exits("read ns");
		}
		if(n < 0) {
			fprint(2, "ns: read %r\n");
			exits("read ns");
		}
		if(n == 0)
			break;
		buf[n] = '\0';

		m = mallocz(sizeof(Mount), 1);
		if(m == nil) {
			fprint(2, "ns: no memory: %r\n");
			exits("no memory");
		}

		n = tokenize(buf, av, 5);
		switch(n){
		case 2:
			if(strcmp(av[0], "cd") == 0){
				Bprint(&stdout, "%s %s\n", av[0], av[1]);
				continue;
			}
			/* fall through */
		default:
			fprint(2, "ns: unrecognized format of ns file: %d elements on line %d\n", n, line);
			exits("format");
		case 5:
			m->cmd = strdup(av[0]);
			m->flag = strdup(av[1]);
			m->new = strdup(av[2]);
			m->old = strdup(av[3]);
			m->spec = strdup(av[4]);
			break;
		case 4:
			if(av[1][0] == '-'){
				m->cmd = strdup(av[0]);
				m->flag = strdup(av[1]);
				m->new = strdup(av[2]);
				m->old = strdup(av[3]);
				m->spec = strdup("");
			}else{
				m->cmd = strdup(av[0]);
				m->flag = strdup("");
				m->new = strdup(av[1]);
				m->old = strdup(av[2]);
				m->spec = strdup(av[3]);
			}
			break;
		case 3:
			m->cmd = strdup(av[0]);
			m->flag = strdup("");
			m->new = strdup(av[1]);
			m->old = strdup(av[2]);
			m->spec = strdup("");
			break;
		}

		if(!rflag && strcmp(m->cmd, "mount")==0)
			xlatemnt(m);

		Bprint(&stdout, "%s %s %s %s %s\n", m->cmd, m->flag,
			quote(m->new), quote(m->old), quote(m->spec));

		free(m->cmd);
		free(m->flag);
		free(m->new);
		free(m->old);
		free(m->spec);
		free(m);
	}

	exits(nil);
}

void
xlatemnt(Mount *m)
{
	int n, fd;
	char *s, *t, *net, *port;
	char buf[256];

	if(strncmp(m->new, "/net/", 5) != 0)
		return;

	s = strdup(m->new);
	net = s+5;
	for(t=net; *t!='/'; t++)
		if(*t == '\0')
			goto Return;
	*t = '\0';
	port = t+1;
	for(t=port; *t!='/'; t++)
		if(*t == '\0')
			goto Return;
	*t = '\0';
	if(strcmp(t+1, "data") != 0)
		goto Return;
	snprint(buf, sizeof buf, "/net/%s/%s/remote", net, port);
	fd = open(buf, OREAD);
	if(fd < 0)
		goto Return;
	n = read(fd, buf, sizeof buf);
	close(fd);
	if(n<=1 || n>sizeof buf)
		goto Return;
	if(buf[n-1] == '\n')
		--n;
	buf[n] = '\0';
	t = malloc(strlen(net)+1+n+1);
	if(t == nil)
		goto Return;
	sprint(t, "%s!%s", net, buf);
	free(m->new);
	m->new = t;

Return:	
	free(s);
}

char*
quote(char *s)
{
	static char buf[3][1024];
	static int i;
	char *p, *ep;

	if(strpbrk(s, " '\\\t#$") == nil)
		return s;
	i = (i+1)%3;
	p = &buf[i][0];
	ep = &buf[i][1024];
	*p++ = '\'';
	while(p < ep-5){
		switch(*s){
		case '\0':
			goto out;
		case '\'':
			*p++ = '\'';
			break;
		}
		*p++ = *s++;
	}
    out:
	*p++ = '\'';
	*p = '\0';
	return buf[i];
}
