| /* 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. */ | 
 |  | 
 |  | 
 | #pragma once | 
 |  | 
 | #include <err.h> | 
 | #include <rendez.h> | 
 | #include <rwlock.h> | 
 | #include <linker_func.h> | 
 | #include <fdtap.h> | 
 | #include <ros/fs.h> | 
 | #include <bitmask.h> | 
 | #include <mm.h> | 
 | #include <sys/uio.h> | 
 | #include <time.h> | 
 |  | 
 | /* | 
 |  * functions (possibly) linked in, complete, from libc. | 
 |  */ | 
 | enum { | 
 | 	UTFmax = 4,		/* maximum bytes per rune */ | 
 | 	Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ | 
 | 	Runeself = 0x80,	/* rune and UTF sequences are the same (<) */ | 
 | 	Runeerror = 0xFFFD,	/* decoding error in UTF */ | 
 | 	Runemax = 0x10FFFF,	/* 21-bit rune */ | 
 | 	Runemask = 0x1FFFFF,	/* bits used by runes (see grep) */ | 
 | 	NUMSIZE32 = 10,	/* max size of formatted 32 bit number (hex or deci) */ | 
 | 	NUMSIZE64 = 20,	/* max size of formatted 64 bit number (hex or deci) */ | 
 | }; | 
 |  | 
 | /* | 
 |  * math | 
 |  */ | 
 | extern int isNaN(double); | 
 | extern int isInf(double, int); | 
 | extern double floor(double); | 
 | extern double frexp(double, int *); | 
 | extern double pow10(int); | 
 |  | 
 | /* | 
 |  * one-of-a-kind | 
 |  */ | 
 | extern char *cleanname(char *unused_char_p_t); | 
 |  | 
 | extern int getfields(char *unused_char_p_t, char **unused_char_pp_t, | 
 | 					 int unused_int, int, char *); | 
 | extern int tokenize(char *unused_char_p_t, char **unused_char_pp_t, int); | 
 | extern int dec64(uint8_t * unused_uint8_p_t, int unused_int, | 
 | 				 char *unused_char_p_t, int); | 
 | extern void qsort(void *, long, long, int (*)(void *, void *)); | 
 |  | 
 | extern int toupper(int); | 
 | extern int myetheraddr(uint8_t * unused_uint8_p_t, char *unused_char_p_t); | 
 | extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t); | 
 |  | 
 | /* | 
 |  * network dialling | 
 |  */ | 
 | #define	NETPATHLEN	40 | 
 |  | 
 | /* | 
 |  * Syscall data structures | 
 |  */ | 
 | #define	MORDER	0x0003	/* mask for bits defining order of mounting */ | 
 | #define	MREPL	0x0000	/* mount replaces object */ | 
 | #define	MBEFORE	0x0001	/* mount goes before others in union directory */ | 
 | #define	MAFTER	0x0002	/* mount goes after others in union directory */ | 
 | #define	MCREATE	0x0004	/* permit creation in mounted directory */ | 
 | #define	MCACHE	0x0010	/* cache some data */ | 
 | #define	MMASK	0x0017	/* all bits on */ | 
 |  | 
 | #define	NCONT	0	/* continue after note */ | 
 | #define	NDFLT	1	/* terminate after note */ | 
 | #define	NSAVE	2	/* clear note but hold state */ | 
 | #define	NRSTR	3	/* restore saved state */ | 
 |  | 
 | #define	STATMAX	65535U	/* max length of machine-independent stat structure */ | 
 | #define	ERRMAX		128	/* max length of error string */ | 
 | #define	KNAMELEN	28	/* max length of name held in kernel */ | 
 |  | 
 | /* bits in Qid.type */ | 
 | #define QTDIR		0x80	/* type bit for directories */ | 
 | #define QTAPPEND	0x40	/* type bit for append only files */ | 
 | #define QTEXCL		0x20	/* type bit for exclusive use files */ | 
 | #define QTMOUNT		0x10	/* type bit for mounted channel */ | 
 | #define QTAUTH		0x08	/* type bit for authentication file */ | 
 | #define QTSYMLINK	0x02	/* type bit for symlinks */ | 
 | #define QTFILE		0x00	/* plain file.  Yeah, a zero.  Fucking 9p. */ | 
 |  | 
 | /* bits in Dir.mode */ | 
 | #define DMDIR		0x80000000	/* mode bit for directories */ | 
 | #define DMAPPEND	0x40000000	/* mode bit for append only files */ | 
 | #define DMEXCL		0x20000000	/* mode bit for exclusive use files */ | 
 | #define DMMOUNT		0x10000000	/* mode bit for mounted channel */ | 
 | #define DMWRITABLE	0x08000000	/* non-standard, for select() */ | 
 | #define DMREADABLE	0x04000000	/* non-standard, for select() */ | 
 | #define DMSYMLINK	0x02000000	/* symlink -- from 9p2000.u */ | 
 | /* The lower parts of dir.mode are the three rwx perms (S_PMASK) */ | 
 | #define DMMODE_BITS (DMDIR | DMAPPEND | DMEXCL | DMMOUNT | DMWRITABLE \ | 
 |                      | DMREADABLE | DMSYMLINK) | 
 |  | 
 | struct qid { | 
 | 	uint64_t path; | 
 | 	uint32_t vers; | 
 | 	uint8_t type; | 
 | }; | 
 |  | 
 | static inline bool qid_is_file(struct qid q) | 
 | { | 
 | 	return (q.type & (QTDIR | QTSYMLINK)) == 0; | 
 | } | 
 |  | 
 | struct dir { | 
 | 	/* system-modified data */ | 
 | 	uint16_t type;		/* server type */ | 
 | 	uint32_t dev;		/* server subtype */ | 
 | 	/* file data */ | 
 | 	struct qid qid;		/* unique id from server */ | 
 | 	uint32_t mode;		/* permissions */ | 
 | 	/* 9p stat has u32 atime (seconds) here */ | 
 | 	/* 9p stat has u32 mtime (seconds) here */ | 
 | 	uint64_t length;	/* file length: see <u.h> */ | 
 | 	char *name;		/* last element of path */ | 
 | 	char *uid;		/* owner name */ | 
 | 	char *gid;		/* group name */ | 
 | 	char *muid;		/* last modifier name */ | 
 | 	char *ext;		/* extensions for special files (symlinks) */ | 
 | 	uint32_t n_uid;		/* numeric owner uid */ | 
 | 	uint32_t n_gid;		/* numeric group id */ | 
 | 	uint32_t n_muid;	/* numeric last modifier id */ | 
 | 	struct timespec atime;	/* last access time */ | 
 | 	struct timespec btime;	/* file creation time */ | 
 | 	struct timespec ctime;	/* last attribute change time */ | 
 | 	struct timespec mtime;	/* last data modification time */ | 
 | }; | 
 |  | 
 | struct waitmsg { | 
 | 	int pid;		/* of loved one */ | 
 | 	uint32_t time[3];	/* of loved one and descendants */ | 
 | 	char msg[ERRMAX];	/* actually variable-size in user mode */ | 
 | }; | 
 |  | 
 | #define	VERSION9P	"9P2000" | 
 |  | 
 | #define	MAXWELEM	16 | 
 |  | 
 | typedef | 
 | 	struct fcall { | 
 | 	uint8_t type; | 
 | 	uint32_t fid; | 
 | 	uint16_t tag; | 
 | 	/* union { */ | 
 | 	/* struct { */ | 
 | 	uint32_t msize;			/* Tversion, Rversion */ | 
 | 	char *version;			/* Tversion, Rversion */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	uint16_t oldtag;		/* Tflush */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	char *ename;			/* Rerror */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	struct qid qid;			/* Rattach, Ropen, Rcreate */ | 
 | 	uint32_t iounit;		/* Ropen, Rcreate */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	struct qid aqid;		/* Rauth */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	uint32_t afid;			/* Tauth, Tattach */ | 
 | 	char *uname;			/* Tauth, Tattach */ | 
 | 	char *aname;			/* Tauth, Tattach */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	uint32_t perm;			/* Tcreate */ | 
 | 	char *name;			/* Tcreate */ | 
 | 	uint8_t mode;			/* Tcreate, Topen */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	uint32_t newfid;		/* Twalk */ | 
 | 	uint16_t nwname;		/* Twalk */ | 
 | 	char *wname[MAXWELEM];		/* Twalk */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	uint16_t nwqid;			/* Rwalk */ | 
 | 	struct qid wqid[MAXWELEM];	/* Rwalk */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	int64_t offset;			/* Tread, Twrite */ | 
 | 	uint32_t count;			/* Tread, Twrite, Rread */ | 
 | 	char *data;			/* Twrite, Rread */ | 
 | 	/* }; */ | 
 | 	/* struct { */ | 
 | 	uint16_t nstat;			/* Twstat, Rstat */ | 
 | 	uint8_t *stat;			/* Twstat, Rstat */ | 
 | 	/* }; */ | 
 | 	/* }; */ | 
 | } fcall; | 
 |  | 
 | #define	GBIT8(p)  ((p)[0]) | 
 | #define	GBIT16(p) ((p)[0]|((p)[1]<<8)) | 
 | #define	GBIT32(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))) | 
 | #define	GBIT64(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\ | 
 | 	((int64_t)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32)) | 
 |  | 
 | #define	PBIT8(p,v)  (p)[0]=(v) | 
 | #define	PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8 | 
 | #define	PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24 | 
 | #define	PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\ | 
 | 		(p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56 | 
 |  | 
 | #define	BIT8SZ	1 | 
 | #define	BIT16SZ	2 | 
 | #define	BIT32SZ	4 | 
 | #define	BIT64SZ	8 | 
 | #define	QIDSZ	(BIT8SZ+BIT32SZ+BIT64SZ) | 
 |  | 
 | /* The 9p STATFIXLENs include the leading 16-bit count.  The count, however, | 
 |  * excludes itself; total size is BIT16SZ + count.  This is the amount of fixed | 
 |  * length data in a stat buffer.  This does not include the strings, but it | 
 |  * includes the string counts (u16s) | 
 |  * | 
 |  * STAT_FIX_LEN_9P is the original 9p stat message: type to length, including | 
 |  * u32 atime and u32 mtime.  This is the bare minimum for a stat that we | 
 |  * receive.  We check in e.g. convM2D for any extra fields. | 
 |  * | 
 |  * STAT_FIX_LEN_AK is the stat message used by Akaros, which includes Eric VH's | 
 |  * extensions and full timespecs.  It is analogous to struct dir, including the | 
 |  * u32s for the legacy atime/mtime.  We always send stats of this size, e.g. in | 
 |  * convD2M. | 
 |  * | 
 |  * Note that the extended stat message has fixed data after the strings, but to | 
 |  * get to this data, you have to jump through the string and their counts | 
 |  * (u16s).  The counts are part of the fixed length, but not the strings.  Also | 
 |  * note that the _AK version has an extra string. */ | 
 | #define STAT_NR_STRINGS_9P 4 | 
 | #define STAT_NR_STRINGS_AK 5 | 
 | #define STAT_FIX_LEN_9P (BIT16SZ +                      /* size */             \ | 
 |                          BIT16SZ +                      /* type */             \ | 
 |                          BIT32SZ +                      /* dev */              \ | 
 |                          QIDSZ +                        /* qid */              \ | 
 |                          BIT32SZ +                      /* mode */             \ | 
 |                          BIT32SZ +                      /* atime u32 */        \ | 
 |                          BIT32SZ +                      /* mtime u32 */        \ | 
 |                          BIT64SZ +                      /* length */           \ | 
 |                          STAT_NR_STRINGS_9P * BIT16SZ + /* string counts */    \ | 
 | 						 0) | 
 | #define __STAT_FIX_LEN_AK_NONSTRING (                                          \ | 
 |                          BIT32SZ +                      /* n_uid */            \ | 
 |                          BIT32SZ +                      /* n_gid */            \ | 
 |                          BIT32SZ +                      /* n_muid */           \ | 
 |                          2 * BIT64SZ +                  /* atime */            \ | 
 |                          2 * BIT64SZ +                  /* btime */            \ | 
 |                          2 * BIT64SZ +                  /* ctime */            \ | 
 |                          2 * BIT64SZ +                  /* mtime */            \ | 
 | 						 0) | 
 | #define STAT_FIX_LEN_AK (STAT_FIX_LEN_9P +                                     \ | 
 |                          (STAT_NR_STRINGS_AK - STAT_NR_STRINGS_9P) * BIT16SZ + \ | 
 |                          __STAT_FIX_LEN_AK_NONSTRING +                         \ | 
 | 						 0) | 
 |  | 
 | #define	NOTAG		(uint16_t)~0U	/* Dummy tag */ | 
 | #define	NOFID		(uint32_t)~0U	/* Dummy fid */ | 
 | #define	IOHDRSZ		24 /* ample room for Twrite/Rread header (iounit) */ | 
 |  | 
 | enum { | 
 | 	Tversion = 100, | 
 | 	Rversion, | 
 | 	Tauth = 102, | 
 | 	Rauth, | 
 | 	Tattach = 104, | 
 | 	Rattach, | 
 | 	Terror = 106,	/* illegal */ | 
 | 	Rerror, | 
 | 	Tflush = 108, | 
 | 	Rflush, | 
 | 	Twalk = 110, | 
 | 	Rwalk, | 
 | 	Topen = 112, | 
 | 	Ropen, | 
 | 	Tcreate = 114, | 
 | 	Rcreate, | 
 | 	Tread = 116, | 
 | 	Rread, | 
 | 	Twrite = 118, | 
 | 	Rwrite, | 
 | 	Tclunk = 120, | 
 | 	Rclunk, | 
 | 	Tremove = 122, | 
 | 	Rremove, | 
 | 	Tstat = 124, | 
 | 	Rstat, | 
 | 	Twstat = 126, | 
 | 	Rwstat, | 
 | 	Tmax, | 
 | }; | 
 |  | 
 | void init_empty_dir(struct dir *d); | 
 | unsigned int convM2S(uint8_t * unused_uint8_p_t, unsigned int unused_int, | 
 | 		     struct fcall *); | 
 | unsigned int convS2M(struct fcall *, uint8_t * unused_uint8_p_t, unsigned int); | 
 | unsigned int sizeS2M(struct fcall *); | 
 |  | 
 | unsigned int convM2kdirent(uint8_t * buf, unsigned int nbuf, struct kdirent *kd, | 
 | 			   char *strs); | 
 | unsigned int convM2kstat(uint8_t * buf, unsigned int nbuf, struct kstat *ks); | 
 |  | 
 | void statcheck(uint8_t *buf, size_t nbuf); | 
 | unsigned int convM2D(uint8_t * unused_uint8_p_t, unsigned int unused_int, | 
 | 		     struct dir *, char *unused_char_p_t); | 
 | unsigned int convD2M(struct dir *, uint8_t * unused_uint8_p_t, unsigned int); | 
 | unsigned int sizeD2M(struct dir *); | 
 |  | 
 | int read9pmsg(int unused_int, void *, unsigned int); | 
 |  | 
 | struct ref { | 
 | 	spinlock_t l; | 
 | 	long ref; | 
 | }; | 
 |  | 
 | struct rept { | 
 | 	spinlock_t l; | 
 | 	struct rendez r; | 
 | 	void *o; | 
 | 	int t; | 
 | 	int (*active) (void *); | 
 | 	int (*ck) (void *, int); | 
 | 	void (*f) (void *);			/* called with VM acquire()'d */ | 
 | }; | 
 |  | 
 | enum { | 
 | 	Nopin = -1 | 
 | }; | 
 |  | 
 | struct talarm { | 
 | 	spinlock_t lock; | 
 | 	struct proc *list; | 
 | }; | 
 |  | 
 | struct alarms { | 
 | 	qlock_t qlock; | 
 | 	struct proc *head; | 
 | }; | 
 |  | 
 | /* | 
 |  * Access types in namec & channel flags | 
 |  */ | 
 | enum { | 
 | 	Aaccess,			/* as in stat, wstat */ | 
 | 	Abind,				/* for left-hand-side of bind */ | 
 | 	Atodir,				/* as in chdir */ | 
 | 	Aopen,				/* for i/o */ | 
 | 	Amount,				/* to be mounted or mounted upon */ | 
 | 	Acreate,			/* is to be created */ | 
 | 	Aremove,			/* will be removed by caller */ | 
 | 	Arename,			/* new_path of a rename */ | 
 |  | 
 | 	/* internal chan flags, used by the kernel only */ | 
 | 	COPEN = 		0x0001,	/* for i/o */ | 
 | 	CMSG = 			0x0002,	/* the message channel for a mount */ | 
 | 	CFREE = 		0x0004,	/* not in use */ | 
 | 	CINTERNAL_FLAGS = (COPEN | CMSG | CFREE), | 
 |  | 
 | 	/* chan/file flags, getable via fcntl/getfl and setably via open and | 
 | 	 * sometimes fcntl/setfl.  those that can't be set cause an error() in | 
 | 	 * fd_setfl. */ | 
 | 	CEXTERNAL_FLAGS = ( | 
 | 	    O_CLOEXEC      | /* (prob should be on the FD, 9ns has it here) */ | 
 | 	    O_REMCLO       | /* remove on close (also, maybe should be on FD) */ | 
 | 	    O_APPEND       | /* append on write */ | 
 | 	    O_NONBLOCK     | /* don't block, can't be set via setfl */ | 
 | 	    O_PATH         | /* path open, just the name, no I/O */ | 
 | 	    0), | 
 | }; | 
 |  | 
 | #define NS_IPCK_SHIFT  2 | 
 | #define NS_UDPCK_SHIFT 3 | 
 | #define NS_TCPCK_SHIFT 4 | 
 | #define NS_PKTCK_SHIFT 5 | 
 | #define NS_TSO_SHIFT 6 | 
 | #define NS_SHIFT_MAX 6 | 
 |  | 
 | enum { | 
 | 	BFREE = (1 << 1), | 
 | 	Bipck = (1 << NS_IPCK_SHIFT),	/* ip checksum (rx) */ | 
 | 	Budpck = (1 << NS_UDPCK_SHIFT),	/* udp checksum (rx), needed (tx) */ | 
 | 	Btcpck = (1 << NS_TCPCK_SHIFT),	/* tcp checksum (rx), needed (tx) */ | 
 | 	Bpktck = (1 << NS_PKTCK_SHIFT),	/* packet checksum (rx, maybe) */ | 
 | 	Btso = (1 << NS_TSO_SHIFT),	/* TSO desired (tx) */ | 
 | }; | 
 | #define BLOCK_META_FLAGS (Bipck | Budpck | Btcpck | Bpktck | Btso) | 
 | #define BLOCK_TRANS_TX_CSUM (Budpck | Btcpck) | 
 | #define BLOCK_RX_CSUM (Bipck | Budpck | Btcpck) | 
 |  | 
 | struct extra_bdata { | 
 | 	uintptr_t base; | 
 | 	/* using u32s for packing reasons.  this means no extras > 4GB */ | 
 | 	uint32_t off; | 
 | 	uint32_t len; | 
 | }; | 
 |  | 
 | struct block { | 
 | 	struct block *next; | 
 | 	struct block *list; | 
 | 	uint8_t *rp;			/* first unconsumed byte */ | 
 | 	uint8_t *wp;			/* first empty byte */ | 
 | 	uint8_t *lim;			/* 1 past the end of the buffer */ | 
 | 	uint8_t *base;			/* start of the buffer */ | 
 | 	void (*free) (struct block *); | 
 | 	uint16_t flag; | 
 | 	uint16_t mss;               	/* TCP MSS for TSO */ | 
 | 	uint16_t network_offset;	/* offset from rp */ | 
 | 	uint16_t transport_offset;	/* offset from rp */ | 
 | 	uint16_t tx_csum_offset;	/* offset from tx_offset to store csum */ | 
 | 	/* might want something to track the next free extra_data slot */ | 
 | 	size_t extra_len; | 
 | 	unsigned int nr_extra_bufs; | 
 | 	struct extra_bdata *extra_data; | 
 | }; | 
 | #define BLEN(s)	((s)->wp - (s)->rp + (s)->extra_len) | 
 | #define BHLEN(s) ((s)->wp - (s)->rp) | 
 | #define BALLOC(s) ((s)->lim - (s)->base + (s)->extra_len) | 
 |  | 
 | struct chan { | 
 | 	spinlock_t lock; | 
 | 	struct kref ref; | 
 | 	struct chan *next;	/* allocation */ | 
 | 	struct chan *link; | 
 | 	int64_t offset;		/* in file */ | 
 | 	int type;		/* ID for device type, e.g. #mnt, #kfs, #ip */ | 
 | 	uint32_t dev;		/* device specific; can be an instance ID */ | 
 | 	uint16_t mode;		/* read/write */ | 
 | 	int flag; | 
 | 	struct qid qid; | 
 | 	int fid;		/* for devmnt */ | 
 | 	uint32_t iounit;	/* chunk size for i/o; 0==default */ | 
 | 	struct mhead *umh;	/* mount point that derived Chan */ | 
 | 	struct chan *umc;	/* channel in union; for union read */ | 
 | 	qlock_t umqlock;	/* serialize unionreads */ | 
 | 	int uri;		/* union read index */ | 
 | 	int dri;		/* devdirread index */ | 
 | 	uint32_t mountid; | 
 | 	struct mntcache *mcp;	/* Mount cache pointer */ | 
 | 	struct mnt *mux;	/* Mnt for clients using me for messages */ | 
 | 	union { | 
 | 		void *aux; | 
 | 		char tag[4];	/* for iproute */ | 
 | 	}; | 
 | 	/* mountpoint, as discovered during walk. | 
 | 	 * Used for rename at present. | 
 | 	 */ | 
 | 	struct chan *mountpoint; | 
 | 	struct chan *mchan;	/* channel to mounted server */ | 
 | 	struct qid mqid;	/* qid of root of mount point */ | 
 | 	struct cname *name; | 
 | 	/* hack for dir reads to try to get them right. */ | 
 | 	int ateof; | 
 | 	void *buf; | 
 | 	int bufused; | 
 | 	/* A lot of synthetic files need something generated at open time, which | 
 | 	 * the user can read from (including offsets) while the underlying file | 
 | 	 * changes.  Hang that buffer here. */ | 
 | 	void *synth_buf; | 
 | }; | 
 |  | 
 | extern struct chan *kern_slash; | 
 |  | 
 | struct cname { | 
 | 	struct kref ref; | 
 | 	int alen;		/* allocated length */ | 
 | 	int len;		/* strlen(s) */ | 
 | 	char *s; | 
 | }; | 
 |  | 
 | struct fs_file; | 
 |  | 
 | struct dev { | 
 | 	char *name; | 
 |  | 
 | 	void (*reset)(void); | 
 | 	void (*init)(void); | 
 | 	void (*shutdown)(void); | 
 | 	struct chan *(*attach)(char *muxattach); | 
 | 	struct walkqid *(*walk)(struct chan *, struct chan *, char **name, | 
 | 	                        unsigned int); | 
 | 	size_t (*stat)(struct chan *, uint8_t *, size_t); | 
 | 	struct chan *(*open)(struct chan *, int); | 
 | 	void (*create)(struct chan *, char *, int, uint32_t, char *); | 
 | 	void (*close)(struct chan *); | 
 | 	size_t (*read)(struct chan *, void *, size_t, off64_t); | 
 | 	struct block *(*bread)(struct chan *, size_t, off64_t); | 
 | 	size_t (*write)(struct chan *, void *, size_t, off64_t); | 
 | 	size_t (*bwrite)(struct chan *, struct block *, off64_t); | 
 | 	void (*remove)(struct chan *); | 
 | 	void (*rename)(struct chan *, struct chan *, const char *, int); | 
 | 	size_t (*wstat)(struct chan *, uint8_t *, size_t); | 
 | 	void (*power)(int);	/* power mgt: power(1) → on, power (0) → off */ | 
 | //  int (*config)( int unused_int, char *unused_char_p_t, DevConf*); | 
 | 	char *(*chaninfo)(struct chan *, char *, size_t); | 
 | 	int (*tapfd)(struct chan *, struct fd_tap *, int); | 
 | 	unsigned long (*chan_ctl)(struct chan *c, int op, unsigned long a1, | 
 | 	                          unsigned long a2, unsigned long a3, | 
 | 	                          unsigned long a4); | 
 | 	struct fs_file *(*mmap)(struct chan *, struct vm_region *, int, int); | 
 | 	/* we need to be aligned to 64 bytes for the linker tables. */ | 
 | } __attribute__ ((aligned(64))); | 
 |  | 
 | struct dirtab { | 
 | 	char name[KNAMELEN]; | 
 | 	struct qid qid; | 
 | 	int64_t length; | 
 | 	int perm; | 
 | 	/* we need to be aligned to 64 bytes for the linker tables. */ | 
 | } __attribute__ ((aligned(64))); | 
 |  | 
 | struct walkqid { | 
 | 	struct chan *clone; | 
 | 	int nqid; | 
 | 	struct qid qid[1]; | 
 | }; | 
 |  | 
 | enum { | 
 | 	NSMAX = 1000, | 
 | 	NSLOG = 7, | 
 | 	NSCACHE = (1 << NSLOG), | 
 | }; | 
 |  | 
 | struct mntwalk {			/* state for /proc/#/ns */ | 
 | 	int cddone; | 
 | 	uint32_t id; | 
 | 	struct mhead *mh; | 
 | 	struct mount *cm; | 
 | }; | 
 |  | 
 | struct mount { | 
 | 	uint32_t mountid; | 
 | 	struct mount *next; | 
 | 	struct mhead *head; | 
 | 	struct mount *copy; | 
 | 	struct mount *order; | 
 | 	struct chan *to;		/* channel replacing channel */ | 
 | 	int mflag; | 
 | 	char *spec; | 
 | }; | 
 |  | 
 | struct mhead { | 
 | 	struct kref ref; | 
 | 	struct rwlock lock; | 
 | 	struct chan *from;		/* channel mounted upon */ | 
 | 	struct mount *mount;		/* what's mounted upon it */ | 
 | 	struct mhead *hash;		/* Hash chain */ | 
 | }; | 
 |  | 
 | struct mnt { | 
 | 	spinlock_t lock; | 
 | 	/* references are counted using c->ref; channels on this mount point | 
 | 	 * incref(c->mchan) == Mnt.c */ | 
 | 	struct chan *c;			/* Channel to file service */ | 
 | 	struct kthread *rip;		/* Reader in progress */ | 
 | 	struct mntrpc *queue;		/* Queue of pending requests on chan */ | 
 | 	uint32_t id;			/* Multiplexer id for channel check */ | 
 | 	struct mnt *list;		/* Free list */ | 
 | 	int flags;			/* cache */ | 
 | 	int msize;			/* data + IOHDRSZ */ | 
 | 	char *version;			/* 9P version */ | 
 | 	struct queue *q;		/* input queue */ | 
 | }; | 
 |  | 
 | enum { | 
 | 	RENDLOG = 5, | 
 | 	RENDHASH = 1 << RENDLOG,	/* Hash to lookup rendezvous tags */ | 
 | 	MNTLOG = 5, | 
 | 	MNTHASH = 1 << MNTLOG,	/* Hash to walk mount table */ | 
 | 	DELTAFD = 20,	/* allocation quantum for process file descriptors */ | 
 | 	MAXNFD = 4000,	/* max per process file descriptors */ | 
 | 	MAXKEY = 8,	/* keys for signed modules */ | 
 | }; | 
 | #define MOUNTH(p,qid)	((p)->mnthash[(qid).path&((1<<MNTLOG)-1)]) | 
 |  | 
 | struct mntparam { | 
 | 	struct chan *chan; | 
 | 	struct chan *authchan; | 
 | 	char *spec; | 
 | }; | 
 |  | 
 | struct pgrp { | 
 | 	struct kref ref;		/* also used as a lock when mounting */ | 
 | 	uint32_t pgrpid; | 
 | 	qlock_t debug;			/* single access via devproc.c */ | 
 | 	struct rwlock ns;		/* Namespace n read/one write lock */ | 
 | 	qlock_t nsh; | 
 | 	struct mhead *mnthash[MNTHASH]; | 
 | 	int progmode; | 
 | 	int nodevs; | 
 | 	int pin; | 
 | }; | 
 |  | 
 | struct evalue { | 
 | 	char *var; | 
 | 	char *val; | 
 | 	int len; | 
 | 	struct qid qid; | 
 | 	struct evalue *next; | 
 | }; | 
 |  | 
 | struct egrp { | 
 | 	struct kref ref; | 
 | 	qlock_t qlock; | 
 | 	struct evalue *entries; | 
 | 	uint32_t path;		/* qid.path of next Evalue to be allocated */ | 
 | 	uint32_t vers;		/* of Egrp */ | 
 | }; | 
 |  | 
 | struct signerkey { | 
 | 	struct kref ref; | 
 | 	char *owner; | 
 | 	uint16_t footprint; | 
 | 	uint32_t expires; | 
 | 	void *alg; | 
 | 	void *pk; | 
 | 	void (*pkfree) (void *); | 
 | }; | 
 |  | 
 | struct skeyset { | 
 | 	struct kref ref; | 
 | 	qlock_t qlock; | 
 | 	uint32_t flags; | 
 | 	char *devs; | 
 | 	int nkey; | 
 | 	struct signerkey *keys[MAXKEY]; | 
 | }; | 
 |  | 
 | /* | 
 |  * fasttick timer interrupts | 
 |  */ | 
 | enum { | 
 | 	/* Mode */ | 
 | 	Trelative,		/* timer programmed in ns from now */ | 
 | 	Tabsolute,		/* timer programmed in ns since epoch */ | 
 | 	Tperiodic,		/* periodic timer, period in ns */ | 
 | }; | 
 |  | 
 | enum { | 
 | 	PRINTSIZE = 256, | 
 | 	NUMSIZE = 12,	/* size of formatted number */ | 
 | 	MB = (1024 * 1024), | 
 | 	READSTR = 2000,	/* temporary buffer size for device reads */ | 
 | }; | 
 |  | 
 | extern struct dev devtab[]; | 
 | extern struct dev __devtabend[]; | 
 |  | 
 | struct cmdbuf { | 
 | 	char *buf; | 
 | 	char **f; | 
 | 	int nf; | 
 | }; | 
 |  | 
 | struct cmdtab { | 
 | 	int index;		/* used by client to switch on result */ | 
 | 	char *cmd;		/* command name */ | 
 | 	int narg;		/* expected #args; 0 ==> variadic */ | 
 | }; | 
 |  | 
 | /* queue state bits, all can be set in qopen (Qstarve is always set) */ | 
 | enum { | 
 | 	Qmsg		= (1 << 1),	/* message stream */ | 
 | 	Qclosed		= (1 << 2),	/* queue has been closed/hungup */ | 
 | 	Qcoalesce	= (1 << 3),	/* coalesce empty packets on read */ | 
 | 	Qkick		= (1 << 4),	/* always call kick() after qwrite */ | 
 | 	Qdropoverflow	= (1 << 5),	/* drop writes that would block */ | 
 | }; | 
 |  | 
 | /* Per-process structs */ | 
 | #define NR_OPEN_FILES_DEFAULT 32 | 
 | #define NR_FILE_DESC_DEFAULT 32 | 
 |  | 
 | /* Bitmask for file descriptors, big for when we exceed the initial small.  We | 
 |  * could just use the fd_array to check for openness instead of the bitmask, | 
 |  * but eventually we might want to use the bitmasks for other things (like | 
 |  * which files are close_on_exec. */ | 
 |  | 
 | typedef struct fd_set { | 
 |     uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_MAX)]; | 
 | } fd_set; | 
 |  | 
 |  | 
 | struct small_fd_set { | 
 |     uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_DEFAULT)]; | 
 | }; | 
 |  | 
 | /* Helper macros to manage fd_sets */ | 
 | #define FD_SET(n, p)	((p)->fds_bits[(n) / 8] |=  (1 << ((n) & 7))) | 
 | #define FD_CLR(n, p)	((p)->fds_bits[(n) / 8] &= ~(1 << ((n) & 7))) | 
 | #define FD_ISSET(n, p)	((p)->fds_bits[(n) / 8] &   (1 << ((n) & 7))) | 
 | #define FD_ZERO(p)		memset((void*)(p), 0, sizeof(*(p))) | 
 |  | 
 | /* Describes an open file.  We need this, since the FD flags are supposed to be | 
 |  * per file descriptor, not per file (like the file status flags). */ | 
 | struct file_desc { | 
 | 	struct chan		*fd_chan; | 
 | 	unsigned int		fd_flags; | 
 | 	struct fd_tap		*fd_tap; | 
 | }; | 
 |  | 
 | /* All open files for a process */ | 
 | struct fd_table { | 
 | 	spinlock_t		lock; | 
 | 	bool			closed; | 
 | 	int			max_files;	/* max files ptd to by fd */ | 
 | 	int			max_fdset;	/* max of the current fd_set */ | 
 | 	int			hint_min_fd;	/* <= min available fd */ | 
 | 	struct file_desc	*fd;		/* initially pts to fd_array */ | 
 | 	struct fd_set		*open_fds;	/* init, pts to open_fds_init */ | 
 | 	struct small_fd_set	open_fds_init; | 
 | 	struct file_desc	fd_array[NR_OPEN_FILES_DEFAULT]; | 
 | }; | 
 |  | 
 | ssize_t kread_file(struct file_or_chan *file, void *buf, size_t sz); | 
 | void *kread_whole_file(struct file_or_chan *file); | 
 |  | 
 | /* Process-related File management functions */ | 
 | void *lookup_fd(struct fd_table *fdt, int fd, bool incref); | 
 | int insert_obj_fdt(struct fd_table *fdt, void *obj, int low_fd, int fd_flags, | 
 |                    bool must_use_low); | 
 | bool close_fd(struct fd_table *fdt, int fd); | 
 | void close_fdt(struct fd_table *open_files, bool cloexec); | 
 | void clone_fdt(struct fd_table *src, struct fd_table *dst); | 
 |  | 
 | #define DEVDOTDOT -1 | 
 |  | 
 | typedef int Devgen(struct chan *, char *unused_char_p_t, struct dirtab *, | 
 | 		   int unused_int, int, struct dir *); | 
 |  | 
 | /* inferno portfns.h. Not all these are needed. */ | 
 | #define		FPinit() fpinit()	/* remove this if math lib is linked */ | 
 | void FPrestore(void *); | 
 | void FPsave(void *); | 
 | struct cname *addelem(struct cname *, char *unused_char_p_t); | 
 | void addprog(struct proc *); | 
 | void addrootfile(char *unused_char_p_t, uint8_t * unused_uint8_p_t, uint32_t); | 
 | struct block *adjustblock(struct block *, int); | 
 | struct block *block_alloc(size_t, int); | 
 | int block_add_extd(struct block *b, unsigned int nr_bufs, int mem_flags); | 
 | int block_append_extra(struct block *b, uintptr_t base, uint32_t off, | 
 |                        uint32_t len, int mem_flags); | 
 | void block_copy_metadata(struct block *new_b, struct block *old_b); | 
 | void block_reset_metadata(struct block *b); | 
 | void block_add_to_offsets(struct block *b, int delta); | 
 | void block_transfer_extras(struct block *new, struct block *old); | 
 | void block_replace_extras(struct block *new, struct block *old); | 
 | struct block *block_realloc(struct block *b, size_t header_space); | 
 | size_t block_copy_to_body(struct block *to, void *from, size_t copy_amt); | 
 | int anyhigher(void); | 
 | int anyready(void); | 
 | void _assert(char *unused_char_p_t); | 
 | struct block *bl2mem(uint8_t * unused_uint8_p_t, struct block *, int); | 
 | int blocklen(struct block *); | 
 | char *channame(struct chan *); | 
 | void cclose(struct chan *); | 
 | void chan_incref(struct chan *); | 
 | void chanfree(struct chan *); | 
 | void chanrec(struct mnt *); | 
 | void checkalarms(void); | 
 | void checkb(struct block *, char *unused_char_p_t); | 
 | struct chan *cclone(struct chan *); | 
 | void cclose(struct chan *); | 
 | void closeegrp(struct egrp *); | 
 | void closemount(struct mount *); | 
 | void closepgrp(struct pgrp *); | 
 | void closesigs(struct skeyset *); | 
 | void debugcmd(struct cmdbuf *cb); | 
 | struct mhead *newmhead(struct chan *from); | 
 | int cmount(struct chan *, struct chan *, int unused_int, char *unused_char_p_t); | 
 | void cnameclose(struct cname *); | 
 | struct block *concatblock(struct block *); | 
 | struct block *linearizeblock(struct block *b); | 
 | void confinit(void); | 
 | void cons_add_char(char c); | 
 | struct block *copyblock(struct block *b, int mem_flags); | 
 | struct chan *cunique(struct chan *); | 
 | struct chan *createdir(struct chan *, struct mhead *); | 
 | void cunmount(struct chan *, struct chan *); | 
 | void cursorenable(void); | 
 | void cursordisable(void); | 
 | int cursoron(int); | 
 | void cursoroff(int); | 
 | struct chan *devattach(const char *name, char *spec); | 
 | struct block *devbread(struct chan *, size_t, off64_t); | 
 | size_t devbwrite(struct chan *, struct block *, off64_t); | 
 | struct chan *devclone(struct chan *); | 
 | void devcreate(struct chan *, char *name, int mode, uint32_t perm, char *ext); | 
 | void devdir(struct chan *, struct qid, char *, int64_t, char *, long, | 
 | 	    struct dir *); | 
 | long devdirread(struct chan *, char *, long, struct dirtab *, int, Devgen *); | 
 | Devgen devgen; | 
 | void devinit(void); | 
 | int devno(const char *name, int user); | 
 | void devpower(int); | 
 | struct dev *devbyname(char *unused_char_p_t); | 
 | struct chan *devopen(struct chan *, int unused_int, struct dirtab *, | 
 | 		     int unused_int2, Devgen *); | 
 | void devpermcheck(char *unused_char_p_t, uint32_t, int); | 
 | void devremove(struct chan *); | 
 | void devreset(void); | 
 | void devshutdown(void); | 
 | size_t dev_make_stat(struct chan *c, struct dir *dir, uint8_t *dp, size_t n); | 
 | size_t devstat(struct chan *, uint8_t *db, size_t n, struct dirtab *, | 
 |                int ntab, Devgen *); | 
 | struct walkqid *devwalk(struct chan *, struct chan *, char **unused_char_pp_t, | 
 | 			int unused_int, struct dirtab *, int unused_intw, | 
 | 			Devgen *); | 
 | size_t devwstat(struct chan *, uint8_t *, size_t); | 
 | char *devchaninfo(struct chan *chan, char *ret, size_t ret_l); | 
 | void disinit(void *); | 
 | void disfault(void *, char *unused_char_p_t); | 
 | int domount(struct chan **, struct mhead **); | 
 | void drawactive(int); | 
 | void drawcmap(void); | 
 | void dumpstack(void); | 
 | void egrpcpy(struct egrp *, struct egrp *); | 
 | int emptystr(char *unused_char_p_t); | 
 | int eqchan(struct chan *, struct chan *, int); | 
 | int eqqid(struct qid, struct qid); | 
 |  | 
 | void errstr(char *unused_char_p_t, int); | 
 | void excinit(void); | 
 | void exit(int); | 
 | void reboot(void); | 
 | void halt(void); | 
 | int export(int unused_int, char *unused_char_p_t, int); | 
 | uint64_t fastticks(uint64_t *); | 
 | uint64_t fastticks2ns(uint64_t); | 
 | int findmount(struct chan **, struct mhead **, int unused_int, int, struct qid); | 
 | void free_block_extra(struct block *); | 
 | size_t freeb(struct block *b); | 
 | size_t freeblist(struct block *b); | 
 | void freeskey(struct signerkey *); | 
 | void getcolor(uint32_t, uint32_t *, uint32_t *, uint32_t *); | 
 | uint32_t getmalloctag(void *); | 
 | uint32_t getrealloctag(void *); | 
 | void printblock(struct block *b); | 
 | void ilock(spinlock_t *); | 
 | int iprint(char *unused_char_p_t, ...); | 
 | void isdir(struct chan *); | 
 | int islo(void); | 
 | void iunlock(spinlock_t *); | 
 | void ixsummary(void); | 
 | void kbdclock(void); | 
 | int kbdcr2nl(struct queue *, int); | 
 | int kbdputc(struct queue *, int); | 
 | void kbdrepeat(int); | 
 | void kproc(char *unused_char_p_t, void (*)(void *), void *, int); | 
 | void kprocchild(struct proc *, void (*)(void *), void *); | 
 | void (*kproftick) (uint32_t); | 
 | void ksetenv(char *unused_char_p_t, char *, int); | 
 | void kstrdup(char **cp, char *name); | 
 |  | 
 | struct block *mem2bl(uint8_t * unused_uint8_p_t, int); | 
 | int memusehigh(void); | 
 | void microdelay(int); | 
 | uint64_t mk64fract(uint64_t, uint64_t); | 
 | void mkqid(struct qid *, int64_t, uint32_t, int); | 
 | void modinit(void); | 
 | struct chan *mntauth(struct chan *, char *unused_char_p_t); | 
 | long mntversion(struct chan *, char *unused_char_p_t, int unused_int, int); | 
 | void mountfree(struct mount *); | 
 | void mousetrack(int unused_int, int, int, int); | 
 | uint64_t ms2fastticks(uint32_t); | 
 | void mul64fract(uint64_t *, uint64_t, uint64_t); | 
 | void muxclose(struct mnt *); | 
 | struct chan *namec(char *unused_char_p_t, int unused_int, int, uint32_t, | 
 |                    void *ext); | 
 | struct chan *namec_from(struct chan *c, char *name, int amode, int omode, | 
 |                         uint32_t perm, void *ext); | 
 | struct chan *newchan(void); | 
 | struct egrp *newegrp(void); | 
 | struct mount *newmount(struct mhead *, struct chan *, int unused_int, | 
 | 		       char *unused_char_p_t); | 
 | struct pgrp *newpgrp(void); | 
 | struct proc *newproc(void); | 
 | char *nextelem(char *unused_char_p_t, char *); | 
 |  | 
 | struct cname *newcname(char *unused_char_p_t); | 
 | void notkilled(void); | 
 | uint32_t random_read(void *xp, uint32_t n); | 
 | uint32_t urandom_read(void *xp, uint32_t n); | 
 | uint64_t ns2fastticks(uint64_t); | 
 | int okaddr(uint32_t, uint32_t, int); | 
 | int omode_to_rwx(int); | 
 | int omode_to_9p_accmode(int open_flags); | 
 | int access_bits_to_omode(int access_bits); | 
 | struct block *packblock(struct block *); | 
 | struct block *padblock(struct block *, int); | 
 |  | 
 | void pgrpcpy(struct pgrp *, struct pgrp *); | 
 |  | 
 | int progfdprint(struct chan *, int unused_int, int, char *unused_char_p_t, | 
 | 		int i); | 
 | int pullblock(struct block **, int); | 
 | struct block *pullupblock(struct block *b, size_t n); | 
 | struct block *pullupqueue(struct queue *b, size_t n); | 
 | void putmhead(struct mhead *); | 
 | void putstrn(char *unused_char_p_t, int); | 
 | void qaddlist(struct queue *, struct block *); | 
 | struct block *qbread(struct queue *q, size_t len); | 
 | struct block *qbread_nonblock(struct queue *q, size_t len); | 
 | ssize_t qbwrite(struct queue *, struct block *); | 
 | ssize_t qbwrite_nonblock(struct queue *, struct block *); | 
 | ssize_t qibwrite(struct queue *q, struct block *b); | 
 | struct queue *qbypass(void (*)(void *, struct block *), void *); | 
 | int qcanread(struct queue *); | 
 | void qclose(struct queue *); | 
 | struct block *qcopy(struct queue *, int unused_int, uint32_t); | 
 | struct block *qclone(struct queue *q, int header_len, int len, | 
 |                      uint32_t offset); | 
 | struct block *blist_clone(struct block *blist, int header_len, int len, | 
 |                           uint32_t offset); | 
 | size_t qdiscard(struct queue *q, size_t len); | 
 | void qflush(struct queue *); | 
 | void qfree(struct queue *); | 
 | int qfull(struct queue *); | 
 | struct block *qget(struct queue *); | 
 | void qhangup(struct queue *, char *unused_char_p_t); | 
 | int qisclosed(struct queue *); | 
 | ssize_t qiwrite(struct queue *, void *, int); | 
 | int qlen(struct queue *); | 
 | size_t q_bytes_read(struct queue *q); | 
 | void qdropoverflow(struct queue *, bool); | 
 | void q_toggle_qmsg(struct queue *q, bool onoff); | 
 | void q_toggle_qcoalesce(struct queue *q, bool onoff); | 
 | struct queue *qopen(int unused_int, int, void (*)(void *), void *); | 
 | ssize_t qpass(struct queue *, struct block *); | 
 | ssize_t qpassnolim(struct queue *, struct block *); | 
 | void qputback(struct queue *, struct block *); | 
 | size_t qread(struct queue *q, void *va, size_t len); | 
 | size_t qread_nonblock(struct queue *q, void *va, size_t len); | 
 | void qreopen(struct queue *); | 
 | void qsetlimit(struct queue *, size_t); | 
 | size_t qgetlimit(struct queue *); | 
 | int qwindow(struct queue *); | 
 | ssize_t qwrite(struct queue *, void *, int); | 
 | ssize_t qwrite_nonblock(struct queue *, void *, int); | 
 | typedef void (*qio_wake_cb_t)(struct queue *q, void *data, int filter); | 
 | void qio_set_wake_cb(struct queue *q, qio_wake_cb_t func, void *data); | 
 | bool qreadable(struct queue *q); | 
 | bool qwritable(struct queue *q); | 
 |  | 
 | void *realloc(void *, uint32_t); | 
 | int readmem(unsigned long offset, char *buf, unsigned long n, const void *mem, | 
 | 	    size_t mem_len); | 
 | int readnum(unsigned long off, char *buf, unsigned long n, unsigned long val, | 
 | 	    size_t size); | 
 | int readnum_hex(unsigned long off, char *buf, unsigned long n, | 
 |                 unsigned long val, size_t size); | 
 | int readstr(unsigned long offset, char *buf, unsigned long n, const char *str); | 
 | int readnum_int64_t(uint32_t, char *unused_char_p_t, uint32_t, int64_t, int); | 
 | unsigned long strtoul_from_ubuf(void *ubuf, size_t count, int base); | 
 | void ready(struct proc *); | 
 | void renameproguser(char *unused_char_p_t, char *); | 
 | void renameuser(char *unused_char_p_t, char *); | 
 | void resrcwait(char *unused_char_p_t); | 
 | struct proc *runproc(void); | 
 | void (*serwrite) (char *unused_char_p_t, int); | 
 | int setcolor(uint32_t, uint32_t, uint32_t, uint32_t); | 
 |  | 
 | void setmalloctag(void *, uint32_t); | 
 | int setpri(int); | 
 | void setrealloctag(void *, uint32_t); | 
 | char *skipslash(char *unused_char_p_t); | 
 | void *smalloc(uint32_t); | 
 | int splhi(void); | 
 | int spllo(void); | 
 | void splx(int); | 
 | void splxpc(int); | 
 | void swiproc(struct proc *, int); | 
 | uint32_t _tas(uint32_t *); | 
 | uint32_t tk2ms(uint32_t); | 
 | #define		TK2MS(x) ((x)*(1000/HZ)) | 
 | uint64_t tod2fastticks(int64_t); | 
 | int64_t todget(int64_t *); | 
 | void todfix(void); | 
 | void todsetfreq(int64_t); | 
 | void todinit(void); | 
 | void todset(int64_t, int64_t, int); | 
 | int tready(void *); | 
 | struct block *trimblock(struct block *, int unused_int, int); | 
 | int uartgetc(void); | 
 | void uartputc(int); | 
 | void uartputs(char *unused_char_p_t, int); | 
 | void unlock(spinlock_t *); | 
 | void userinit(void); | 
 | uint32_t userpc(void); | 
 | void validname(char *, int); | 
 | void validwstatname(char *); | 
 | void *xalloc(uint32_t); | 
 | void *xallocz(uint32_t, int); | 
 | void xfree(void *); | 
 | void xhole(uint32_t, uint32_t); | 
 | void xinit(void); | 
 | int xmerge(void *, void *); | 
 | void *xspanalloc(uint32_t, int unused_int, uint32_t); | 
 | void xsummary(void); | 
 |  | 
 | void validaddr(void *, uint32_t, int); | 
 | void *vmemchr(void *, int unused_int, int); | 
 | void hnputv(void *, int64_t); | 
 | void hnputl(void *, uint32_t); | 
 | void hnputs(void *, uint16_t); | 
 | int64_t nhgetv(void *); | 
 | uint32_t nhgetl(void *); | 
 | uint16_t nhgets(void *); | 
 |  | 
 | char *get_cur_genbuf(void); | 
 |  | 
 | static inline const char *chan_dev_name(struct chan *c) | 
 | { | 
 | 	return devtab[c->type].name; | 
 | } | 
 |  | 
 | /* hack for now. */ | 
 | #define	NOW	tsc2msec(read_tsc()) | 
 | #define	seconds() tsc2sec(read_tsc()) | 
 | #define	milliseconds() tsc2msec(read_tsc()) | 
 |  | 
 | /* kern/drivers/dev/tab.c */ | 
 | void devtabinit(); | 
 | void devtabreset(); | 
 |  | 
 | /* kern/src/ns/parse.c */ | 
 | struct cmdbuf *parsecmd(char *p, size_t n); | 
 | void cmderror(struct cmdbuf *cb, char *s); | 
 | struct cmdtab *lookupcmd(struct cmdbuf *cb, struct cmdtab *ctab, int nctab); | 
 |  | 
 | /* kern/src/ns/sysfile.c */ | 
 | int newfd(struct chan *c, int low_fd, int oflags, bool must_use_low); | 
 | struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt, | 
 |                       int iref); | 
 | long kchanio(void *vc, void *buf, int n, int mode); | 
 | int openmode(uint32_t o); | 
 | void fdclose(struct fd_table *fdt, int fd); | 
 | int syschdir(struct proc *target, char *path); | 
 | int sysfchdir(struct proc *target, int fd); | 
 | int grpclose(struct fd_table *fdt, int fd); | 
 | int sysclose(int fd); | 
 | int syscreate(char *path, int mode, uint32_t perm); | 
 | int sysdup(int old, int low_fd, bool must_use_low); | 
 | int sys_dup_to(struct proc *from_proc, unsigned int from_fd, | 
 |                struct proc *to_proc, unsigned int to_fd); | 
 | int sysfstat(int fd, uint8_t*, int n); | 
 | int sysfstatakaros(int fd, struct kstat *); | 
 | char *sysgetcwd(void); | 
 | int sysfauth(int fd, char *aname); | 
 | int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen); | 
 | int sysfwstat(int fd, uint8_t * buf, int n); | 
 | long bindmount(struct chan *c, char *old, int flag, char *spec); | 
 | int sysbind(char *new, char *old, int flags); | 
 | int syssymlink(char *new_path, char *old_path); | 
 | int sysmount(int fd, int afd, char *old, int flags, char *spec); | 
 | int sysunmount(char *old, char *new); | 
 | int sysopenat(int dirfd, char *path, int vfs_flags, int perm); | 
 | int sysopen(char *path, int vfs_flags); | 
 | long unionread(struct chan *c, void *va, long n); | 
 | void read_exactly_n(struct chan *c, void *vp, long n); | 
 | long sysread(int fd, void *va, long n); | 
 | long syspread(int fd, void *va, long n, int64_t off); | 
 | int sysremove(char *path); | 
 | int sysrename(char *from_path, char *to_path); | 
 | int64_t sysseek(int fd, int64_t off, int whence); | 
 | void validstat(uint8_t * s, int n, int slashok); | 
 | int sysstat(char *path, uint8_t*, int n); | 
 | int syslstat(char *path, uint8_t*, int n); | 
 | int sysstatakaros(char *path, struct kstat *, int flags); | 
 | long syswrite(int fd, void *va, long n); | 
 | long syspwrite(int fd, void *va, long n, int64_t off); | 
 | int syswstat(char *path, uint8_t * buf, int n); | 
 | struct dir *chandirstat(struct chan *c); | 
 | struct dir *sysdirstat(char *name); | 
 | struct dir *sysdirlstat(char *name); | 
 | struct dir *sysdirfstat(int fd); | 
 | int sysdirwstat(char *name, struct dir *dir); | 
 | int sysdirfwstat(int fd, struct dir *dir); | 
 | long sysdirread(int fd, struct kdirent **d); | 
 | int sysiounit(int fd); | 
 | void print_chaninfo(struct chan *ch); | 
 | int plan9setup(struct proc *new_proc, struct proc *parent, int flags); | 
 | int iseve(void); | 
 | int fd_getfl(int fd); | 
 | int fd_chan_ctl(int fd, int cmd, unsigned long arg1, unsigned long arg2, | 
 |                 unsigned long arg3, unsigned long arg4); | 
 | int fd_get_fd_flags(struct fd_table *fdt, int fd); | 
 | int fd_set_fd_flags(struct fd_table *fdt, int fd, int new_fl); | 
 |  | 
 | /* kern/drivers/dev/srv.c */ | 
 | char *srvname(struct chan *c); | 
 |  | 
 | /* kern/src/eipconv.c. Put them here or face real include hell. */ | 
 | void printqid(void (*putch) (int, void **), void **putdat, struct qid *q); | 
 | void printcname(void (*putch) (int, void **), void **putdat, struct cname *c); | 
 | void printchan(void (*putch) (int, void **), void **putdat, struct chan *c); | 
 |  | 
 | /* kern/src/ns/util.c */ | 
 | bool caller_is_username(char *uid); | 
 | bool caller_has_perms(char *fileuid, uint32_t perm, int omode); | 
 | bool caller_has_dir_perms(struct dir *dir, int omode); | 
 | void dir_perm_check(struct dir *dir, int omode); | 
 |  | 
 | static inline int abs(int a) | 
 | { | 
 | 	if (a < 0) | 
 | 		return -a; | 
 | 	return a; | 
 | } | 
 |  | 
 | extern struct username eve; | 
 | extern unsigned int qiomaxatomic; | 
 |  | 
 | /* special sections */ | 
 | #define __devtab  __attribute__((__section__(".devtab"))) | 
 |  | 
 | #define DEVVARS_ENTRY(name, fmt)                                               \ | 
 | struct dirtab __attribute__((__section__("devvars"))) __devvars_##name =       \ | 
 |               {#name "!" fmt,                                                  \ | 
 |                {(uint64_t)&(name), 0, QTFILE},                                 \ | 
 |                sizeof((name)),                                                 \ | 
 |                0444} |