1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <9pclient.h>
5 #include "plumb.h"
6 
7 static CFsys *fsplumb;
8 static int pfd = -1;
9 static CFid *pfid;
10 
11 int
plumbunmount(void)12 plumbunmount(void)
13 {
14 	CFsys *fsys;
15 
16 	if(fsplumb){
17 		fsys = fsplumb;
18 		fsplumb = nil;
19 		fsunmount(fsys);
20 	}
21 	return 0;
22 }
23 
24 int
plumbopen(char * name,int omode)25 plumbopen(char *name, int omode)
26 {
27 	if(fsplumb == nil)
28 		fsplumb = nsmount("plumb", "");
29 	if(fsplumb == nil)
30 		return -1;
31 	/*
32 	* It's important that when we send something,
33 	* we find out whether it was a valid plumb write.
34 	* (If it isn't, the client might fall back to some
35 	* other mechanism or indicate to the user what happened.)
36 	* We can't use a pipe for this, so we have to use the
37 	* fid interface.  But we need to return a fd.
38 	* Return a fd for /dev/null so that we return a unique
39 	* file descriptor.  In plumbsend we'll look for pfd
40 	* and use the recorded fid instead.
41 	*/
42 	if((omode&3) == OWRITE){
43 		if(pfd != -1){
44 			werrstr("already have plumb send open");
45 			return -1;
46 		}
47 		pfd = open("/dev/null", OWRITE);
48 		if(pfd < 0)
49 			return -1;
50 		pfid = fsopen(fsplumb, name, omode);
51 		if(pfid == nil){
52 			close(pfd);
53 			pfd = -1;
54 			return -1;
55 		}
56 		return pfd;
57 	}
58 
59 	return fsopenfd(fsplumb, name, omode);
60 }
61 
62 CFid*
plumbopenfid(char * name,int mode)63 plumbopenfid(char *name, int mode)
64 {
65 	if(fsplumb == nil){
66 		fsplumb = nsmount("plumb", "");
67 		if(fsplumb == nil){
68 			werrstr("mount plumb: %r");
69 			return nil;
70 		}
71 	}
72 	return fsopen(fsplumb, name, mode);
73 }
74 
75 int
plumbsendtofid(CFid * fid,Plumbmsg * m)76 plumbsendtofid(CFid *fid, Plumbmsg *m)
77 {
78 	char *buf;
79 	int n;
80 
81 	if(fid == nil){
82 		werrstr("invalid fid");
83 		return -1;
84 	}
85 	buf = plumbpack(m, &n);
86 	if(buf == nil)
87 		return -1;
88 	n = fswrite(fid, buf, n);
89 	free(buf);
90 	return n;
91 }
92 
93 int
plumbsend(int fd,Plumbmsg * m)94 plumbsend(int fd, Plumbmsg *m)
95 {
96 	if(fd == -1){
97 		werrstr("invalid fd");
98 		return -1;
99 	}
100 	if(fd != pfd){
101 		werrstr("fd is not the plumber");
102 		return -1;
103 	}
104 	return plumbsendtofid(pfid, m);
105 }
106 
107 Plumbmsg*
plumbrecv(int fd)108 plumbrecv(int fd)
109 {
110 	char *buf;
111 	Plumbmsg *m;
112 	int n, more;
113 
114 	buf = malloc(8192);
115 	if(buf == nil)
116 		return nil;
117 	n = read(fd, buf, 8192);
118 	m = nil;
119 	if(n > 0){
120 		m = plumbunpackpartial(buf, n, &more);
121 		if(m==nil && more>0){
122 			/* we now know how many more bytes to read for complete message */
123 			buf = realloc(buf, n+more);
124 			if(buf == nil)
125 				return nil;
126 			if(readn(fd, buf+n, more) == more)
127 				m = plumbunpackpartial(buf, n+more, nil);
128 		}
129 	}
130 	free(buf);
131 	return m;
132 }
133 
134 Plumbmsg*
plumbrecvfid(CFid * fid)135 plumbrecvfid(CFid *fid)
136 {
137 	char *buf;
138 	Plumbmsg *m;
139 	int n, more;
140 
141 	if(fid == nil){
142 		werrstr("invalid fid");
143 		return nil;
144 	}
145 	buf = malloc(8192);
146 	if(buf == nil)
147 		return nil;
148 	n = fsread(fid, buf, 8192);
149 	m = nil;
150 	if(n > 0){
151 		m = plumbunpackpartial(buf, n, &more);
152 		if(m==nil && more>0){
153 			/* we now know how many more bytes to read for complete message */
154 			buf = realloc(buf, n+more);
155 			if(buf == nil)
156 				return nil;
157 			if(fsreadn(fid, buf+n, more) == more)
158 				m = plumbunpackpartial(buf, n+more, nil);
159 		}
160 	}
161 	free(buf);
162 	return m;
163 }
164