| /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved. | 
 |  * Portions Copyright © 1997-1999 Vita Nuova Limited | 
 |  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited | 
 |  *                                (www.vitanuova.com) | 
 |  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others | 
 |  * | 
 |  * Modified for the Akaros operating system: | 
 |  * Copyright (c) 2013-2014 The Regents of the University of California | 
 |  * Copyright (c) 2013-2015 Google Inc. | 
 |  * | 
 |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
 |  * of this software and associated documentation files (the "Software"), to deal | 
 |  * in the Software without restriction, including without limitation the rights | 
 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
 |  * copies of the Software, and to permit persons to whom the Software is | 
 |  * furnished to do so, subject to the following conditions: | 
 |  * | 
 |  * The above copyright notice and this permission notice shall be included in | 
 |  * all copies or substantial portions of the Software. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | 
 |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
 |  * SOFTWARE. */ | 
 |  | 
 | #include <vfs.h> | 
 | #include <kfs.h> | 
 | #include <slab.h> | 
 | #include <kmalloc.h> | 
 | #include <kref.h> | 
 | #include <string.h> | 
 | #include <stdio.h> | 
 | #include <assert.h> | 
 | #include <error.h> | 
 | #include <cpio.h> | 
 | #include <pmap.h> | 
 | #include <smp.h> | 
 | #include <net/ip.h> | 
 | #include <umem.h> | 
 |  | 
 | struct dev rootdevtab; | 
 |  | 
 | static char *devname(void) | 
 | { | 
 | 	return rootdevtab.name; | 
 | } | 
 |  | 
 | /* make it a power of 2 and nobody gets hurt */ | 
 | #define MAXFILE 1024 | 
 | int rootmaxq = MAXFILE; | 
 |  | 
 | /* TODO: | 
 |  *  - synchronization!  what needs protection from concurrent use, etc. | 
 |  * 	- clean up documentation and whatnot | 
 |  * 	- does remove, mkdir, rmdir work? | 
 |  * 	- fill this with cpio stuff | 
 |  * 	- figure out how to use the page cache | 
 |  * 	- atime/ctime/mtime/etctime | 
 |  */ | 
 |  | 
 | /* this gives you some idea of how much I like linked lists. Just make | 
 |  * a big old table. Later on we can put next and prev indices into the | 
 |  * data if we want but, our current kfs is 1-3 levels deep and very small | 
 |  * (< 200 entries) so I doubt we'll need to do that. It just makes debugging | 
 |  * memory a tad easier. | 
 |  */ | 
 | /* Da Rules. | 
 |  * The roottab contains [name, qid, length, perm]. | 
 |  * Length is filesize for files, # children/elements for dirs | 
 |  * Qid is [path, vers, type]. Path is me. vers is next. Type is QTDIR for dir | 
 |  * and QTFILE for file and 0 for empty. | 
 |  * | 
 |  * We have rootdata to help out with a couple things, notably storing the 'data' | 
 |  * of the object (file or dir) and the first child index/qid.path for | 
 |  * directories. | 
 |  * | 
 |  * Data is [dotdot, child, ptr] | 
 |  * dotdot is .. | 
 |  * ptr is data for files, first child for dirs. | 
 |  * child is the qid.path of the first child of a directory. | 
 |  * Possibly 0 == no child. | 
 |  * To find the next sibling (in a directory), look at roottab[i].qid.vers. | 
 |  */ | 
 |  | 
 | /* we pack the qid as follows: path is the index, vers is ., and type is type */ | 
 |  | 
 | /* Inferno seems to want to: perm |= DMDIR.  It gets checked in other places. | 
 |  * NxM didn't want this, IIRC. | 
 |  * | 
 |  * Also note that "" (/, #root, whatever) has no vers/next/sibling. | 
 |  * | 
 |  * If you want to add new entries, add it to the roottab such that the linked | 
 |  * list of indexes is a cycle (change the last current one), then add an entry | 
 |  * to rootdata, and then change the first rootdata entry to have another entry. | 
 |  * Yeah, it's a pain in the ass. | 
 |  * | 
 |  * To add subdirectories, or any child of a directory, the files (e.g. env_dir1) | 
 |  * go in roottab.  Children of a parent are linked with their vers (note | 
 |  * env_dir1 points to env_dir2), and the last item's vers = 0.  These files need | 
 |  * their dotdot set in rootdata to the qid of their parent.  The directory that | 
 |  * has children needs its child pointer set to the first qid in the list, and | 
 |  * its data pointer must point to the roottab entry for the child.  This also | 
 |  * means that all child entries in roottab for a parent must be contiguous. | 
 |  * | 
 |  * Yeah, it's a pain in the ass.  And, given this structure, it probably can't | 
 |  * grow dynamically (I think we assume roottab[i] = entry for qid.path all over | 
 |  * the place - imagine what happens if we wanted to squeeze in a new entry). */ | 
 | struct dirtab roottab[MAXFILE] = { | 
 | 	{"",				{ 0,  0, QTDIR}, 13, DMDIR | 0777}, | 
 | 	{"chan",			{ 1,  2, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"dev",				{ 2,  3, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"fd",				{ 3,  4, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"prog",			{ 4,  5, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"prof",			{ 5,  6, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"net",				{ 6,  7, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"net.alt",			{ 7,  8, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"nvfs",			{ 8,  9, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"env",				{ 9, 10, QTDIR},  2, DMDIR | 0777}, | 
 | 	{"root",			{10, 11, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"srv",				{11, 12, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"mnt",				{12, 13, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"proc",			{13,  0, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"env_dir1",		{14, 15, QTDIR},  0, DMDIR | 0777}, | 
 | 	{"env_dir2",		{15,  0, QTDIR},  0, DMDIR | 0777}, | 
 | }; | 
 |  | 
 | struct rootdata { | 
 | 	int dotdot; | 
 | 	int child; | 
 | 	void *ptr; | 
 | }; | 
 |  | 
 | struct rootdata rootdata[MAXFILE] = { | 
 | 	{0,	1,	 &roottab[1]}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	14,	 &roottab[14]}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{0,	0,	 NULL}, | 
 | 	{9,	0,	 NULL}, | 
 | 	{9,	0,	 NULL}, | 
 | }; | 
 |  | 
 | /* this is super useful */ | 
 | void dumprootdev(void) | 
 | { | 
 | 	struct dirtab *r = roottab; | 
 | 	struct rootdata *rd = rootdata; | 
 | 	int i; | 
 |  | 
 | 	printk("[       dirtab     ]                          name: [pth, ver, typ],   len,        perm,  .., chld,       data pointer\n"); | 
 | 	for (i = 0; i < rootmaxq; i++, r++, rd++) { | 
 | 		if (i && (!r->name[0])) | 
 | 			continue; | 
 | 		printk("[%p]%30s: [%3d, %3d, %3d], %5d, %11o,", | 
 | 			   r, | 
 | 			   r->name, r->qid.path, r->qid.vers, r->qid.type, | 
 | 			   r->length, r->perm); | 
 | 		printk(" %3d, %4d, %p\n", rd->dotdot, rd->child, rd->ptr); | 
 | 	} | 
 | } | 
 |  | 
 | static int findempty(void) | 
 | { | 
 | 	int i; | 
 | 	for (i = 0; i < rootmaxq; i++) { | 
 | 		if (!roottab[i].qid.type) { | 
 | 			memset(&roottab[i], 0, sizeof(roottab[i])); | 
 | 			return i; | 
 | 		} | 
 | 	} | 
 | 	return -1; | 
 | } | 
 |  | 
 | static void freeempty(int i) | 
 | { | 
 | 	roottab[i].qid.type = 0; | 
 | } | 
 |  | 
 | static int newentry(int parent) | 
 | { | 
 | 	int n = findempty(); | 
 | 	int sib; | 
 | 	if (n < 0) | 
 | 		error(EFAIL, "#root. No more"); | 
 | 	printd("new entry is %d\n", n); | 
 | 	/* add the new one to the head of the linked list.  vers is 'next' */ | 
 | 	roottab[n].qid.vers = rootdata[parent].child; | 
 | 	rootdata[parent].child = n; | 
 | 	return n; | 
 | } | 
 |  | 
 | static int createentry(int dir, char *name, int omode, int perm) | 
 | { | 
 | 	int n = newentry(dir); | 
 | 	strlcpy(roottab[n].name, name, sizeof(roottab[n].name)); | 
 | 	roottab[n].length = 0; | 
 | 	roottab[n].perm = perm; | 
 | 	/* vers is already properly set. */ | 
 | 	mkqid(&roottab[n].qid, n, roottab[n].qid.vers, | 
 | 	      perm & DMDIR ? QTDIR : QTFILE); | 
 | 	rootdata[n].dotdot = roottab[dir].qid.path; | 
 | 	rootdata[dir].ptr = &roottab[n]; | 
 | 	return n; | 
 | } | 
 |  | 
 | static void rootinit(void) | 
 | { | 
 | } | 
 |  | 
 | static struct chan *rootattach(char *spec) | 
 | { | 
 | 	struct chan *c; | 
 | 	if (*spec) | 
 | 		error(EINVAL, ERROR_FIXME); | 
 | 	c = devattach(devname(), spec); | 
 | 	mkqid(&c->qid, roottab[0].qid.path, roottab[0].qid.vers, QTDIR); | 
 | 	return c; | 
 | } | 
 |  | 
 | /* rootgen is unlike other gens when it comes to the dirtab (tab) and ntab (nd). | 
 |  * We actually are a linked list of entries that happen to be in a table.  We | 
 |  * can figure out where to start based on the chan's qid.path and start the gen | 
 |  * from there.  So we don't need the 'tab' from dev.  Likewise, for directories, | 
 |  * we can figure out nd - our length in the dirtab. */ | 
 | static int rootgen(struct chan *c, char *name, struct dirtab *tab_unused, | 
 |                    int nd_unused, int s, struct dir *dp) | 
 | { | 
 | 	int p, i; | 
 | 	struct rootdata *r; | 
 | 	int iter; | 
 | 	struct dirtab *tab; | 
 |  | 
 | 	printd("rootgen from %s, for %s, s %d\n", roottab[c->qid.path].name, name, | 
 | 	       s); | 
 | 	if (s == DEVDOTDOT) { | 
 | 		p = rootdata[c->qid.path].dotdot; | 
 | 		c->qid = roottab[p].qid; | 
 | 		name = roottab[p].name; | 
 | 		devdir(c, c->qid, name, 0, eve.name, 0777, dp); | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	if (c->qid.type != QTDIR) { | 
 | 		/* return ourselved the first time; after that, -1 */ | 
 | 		if (s) | 
 | 			return -1; | 
 | 		tab = &roottab[c->qid.path]; | 
 | 		devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp); | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	if (name != NULL) { | 
 | 		int path = c->qid.path; | 
 | 		isdir(c); | 
 | 		tab = &roottab[rootdata[path].child]; | 
 | 		/* we're starting at a directory. It might be '.' */ | 
 | 		for (iter = 0, i = rootdata[path].child; /* break */; iter++) { | 
 | 			if (strncmp(tab->name, name, KNAMELEN) == 0) { | 
 | 				printd("Rootgen returns 1 for %s\n", name); | 
 | 				devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, | 
 | 				       dp); | 
 | 				printd("return 1 with [%d, %d, %d]\n", dp->qid.path, | 
 | 				       dp->qid.vers, dp->qid.type); | 
 | 				return 1; | 
 | 			} | 
 | 			if (iter > rootmaxq) { | 
 | 				printk("BUG:"); | 
 | 				dumprootdev(); | 
 | 				printk("name %s\n", name); | 
 | 				return -1; | 
 | 			} | 
 | 			i = roottab[i].qid.vers; | 
 | 			if (!i) | 
 | 				break; | 
 | 			tab = &roottab[i]; | 
 | 		} | 
 | 		printd("rootgen: :%s: failed at path %d\n", name, path); | 
 | 		return -1; | 
 | 	} | 
 | 	/* Note we do not provide a "direct gen" for directories, which normally I'd | 
 | 	 * do here.  If we do, that will confuse devdirread, which expects us to | 
 | 	 * list our children, not ourselves.  stat() wants a "direct gen", e.g. for | 
 | 	 * ls -l or stat of a directory.  We can handle that in rootstat(). */ | 
 | 	if (s >= roottab[c->qid.path].length) | 
 | 		return -1; | 
 | 	for (i = rootdata[c->qid.path].child; i; i = roottab[i].qid.vers) { | 
 | 		tab = &roottab[i]; | 
 | 		if (s-- == 0) | 
 | 			break; | 
 | 	} | 
 | 	if (!i) { | 
 | 		warn("#root overflowed 'i', probably a bug"); | 
 | 		return -1; | 
 | 	} | 
 | 	printd("root scan find returns path %p name %s\n", tab->qid.path, tab->name); | 
 | 	devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp); | 
 | 	return 1; | 
 | } | 
 |  | 
 | static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name, | 
 | 								int nname) | 
 | { | 
 | 	return devwalk(c, nc, name, nname, NULL, 0, rootgen); | 
 | } | 
 |  | 
 | /* Instead of using devstat, we use our own.  This allows us to have stats on | 
 |  * directories.  devstat() just fakes it.  Note that gen cannot return a direct | 
 |  * gen for a directory, since that would break devdirread(). */ | 
 | static int rootstat(struct chan *c, uint8_t * dp, int n) | 
 | { | 
 | 	struct dir dir[1]; | 
 | 	ssize_t ret; | 
 | 	struct dirtab *entry = &roottab[c->qid.path]; | 
 |  | 
 | 	/* TODO: this assumes eve is the user, which is what synthetic devices do. | 
 | 	 * Likewise, it sets atime/mtime like a synth device.  There might be other | 
 | 	 * weird things, like qid.type and mode. */ | 
 | 	devdir(c, entry->qid, entry->name, entry->length, eve.name, entry->perm, | 
 | 	       dir); | 
 | 	ret = convD2M(dir, dp, n); | 
 | 	if (!ret) | 
 | 		error(EFAIL, "#root failed to convert stat object to M"); | 
 | 	return ret; | 
 | } | 
 |  | 
 | static struct chan *rootopen(struct chan *c, int omode) | 
 | { | 
 | 	return devopen(c, omode, NULL, 0, rootgen); | 
 | } | 
 |  | 
 | static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm) | 
 | { | 
 | 	struct dirtab *r = &roottab[c->qid.path], *newr; | 
 | 	struct rootdata *rd = &rootdata[c->qid.path]; | 
 | 	/* need to filter openmode so that it gets only the access-type bits */ | 
 | 	omode = openmode(omode); | 
 | 	c->mode = openmode(omode); | 
 | 	printd("rootcreate: c %p, name %s, omode %o, perm %x\n", | 
 | 	       c, name, omode, perm); | 
 | 	/* find an empty slot */ | 
 | 	int path = c->qid.path; | 
 | 	int newfile; | 
 | 	newfile = createentry(path, name, omode, perm); | 
 | 	c->qid = roottab[newfile].qid;	/* need to update c */ | 
 | 	r->length++; | 
 | 	if (newfile > rootmaxq) | 
 | 		rootmaxq = newfile; | 
 | 	printd("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile, | 
 | 	       rootdata[newfile].dotdot, rootmaxq); | 
 | } | 
 |  | 
 | /* | 
 |  * sysremove() knows this is a nop | 
 |  * 		fyi, this isn't true anymore!  they need to set c->type = -1; | 
 |  */ | 
 | static void rootclose(struct chan *c) | 
 | { | 
 | } | 
 |  | 
 | static long rootread(struct chan *c, void *buf, long n, int64_t offset) | 
 | { | 
 | 	uint32_t p, len; | 
 | 	uint8_t *data; | 
 |  | 
 | 	p = c->qid.path; | 
 | 	if (c->qid.type & QTDIR) | 
 | 		return devdirread(c, buf, n, NULL, 0, rootgen); | 
 | 	len = roottab[p].length; | 
 | 	if (offset < 0 || offset >= len) { | 
 | 		return 0; | 
 | 	} | 
 | 	if (offset + n > len) | 
 | 		n = len - offset; | 
 | 	data = rootdata[p].ptr; | 
 | 	/* we can't really claim it has to be a user address. Lots of | 
 | 	 * kernel things read directly, e.g. /dev/reboot, #nix, etc. | 
 | 	 * Address validation should be done in the syscall layer. | 
 | 	 */ | 
 | 	memcpy(buf, data + offset, n); | 
 | 	return n; | 
 | } | 
 |  | 
 | /* For now, just kzmalloc the right amount. Later, we should use | 
 |  * pages so mmap will go smoothly. Would be really nice to have a | 
 |  * kpagemalloc ... barret? | 
 |  * 		we have kpage_alloc (gives a page) and kpage_alloc_addr (void*) | 
 |  */ | 
 | static long rootwrite(struct chan *c, void *a, long n, int64_t off) | 
 | { | 
 | 	struct rootdata *rd = &rootdata[c->qid.path]; | 
 | 	struct dirtab *r = &roottab[c->qid.path]; | 
 |  | 
 | 	if (off < 0) | 
 | 		error(EFAIL, "rootwrite: offset < 0!"); | 
 |  | 
 | 	if (off + n > r->length) { | 
 | 		void *p; | 
 | 		p = krealloc(rd->ptr, off + n, MEM_WAIT); | 
 | 		if (! p) | 
 | 			error(EFAIL, "rootwrite: could not grow the file to %d bytes", | 
 | 				  off + n); | 
 | 		rd->ptr = p; | 
 | 		r->length = off + n; | 
 | 	} | 
 | 	assert(current); | 
 | 	if (memcpy_from_user_errno(current, rd->ptr + off, a, n) < 0) | 
 | 		error(EFAIL, "%s: bad user addr %p", __FUNCTION__, a); | 
 |  | 
 | 	return n; | 
 | } | 
 |  | 
 | static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz) | 
 | { | 
 | 	struct dirtab *file = &roottab[c->qid.path]; | 
 | 	struct dir *dir; | 
 | 	int m_sz; | 
 |  | 
 | 	/* TODO: some security check, Eperm on error */ | 
 |  | 
 | 	/* common trick in wstats.  we want the dir and any strings in the M.  the | 
 | 	 * strings are smaller than entire M (strings plus other M).  the strings | 
 | 	 * will be placed right after the dir (dir[1]) */ | 
 | 	dir = kzmalloc(sizeof(struct dir) + m_buf_sz, MEM_WAIT); | 
 | 	m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]); | 
 | 	if (!m_sz) { | 
 | 		kfree(dir); | 
 | 		error(ENODATA, ERROR_FIXME); | 
 | 	} | 
 | 	/* TODO: handle more things than just the mode */ | 
 | 	if (!emptystr(dir->name)) | 
 | 		printk("[%s] attempted rename of %s to %s\n", __FUNCTION__, | 
 | 		       file->name, dir->name);	/* strncpy for this btw */ | 
 | 	if (dir->mode != -1) | 
 | 		file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0); | 
 | 	kfree(dir); | 
 | 	return m_sz; | 
 | } | 
 |  | 
 | struct dev rootdevtab __devtab = { | 
 | 	.name = "root", | 
 | 	.reset = devreset, | 
 | 	.init = rootinit, | 
 | 	.shutdown = devshutdown, | 
 | 	.attach = rootattach, | 
 | 	.walk = rootwalk, | 
 | 	.stat = rootstat, | 
 | 	.open = rootopen, | 
 | 	.create = rootcreate, | 
 | 	.close = rootclose, | 
 | 	.read = rootread, | 
 | 	.bread = devbread, | 
 | 	.write = rootwrite, | 
 | 	.bwrite = devbwrite, | 
 | 	.remove = devremove, | 
 | 	.wstat = rootwstat, | 
 | 	.power = devpower, | 
 | 	.chaninfo = devchaninfo, | 
 | }; |