1 /*
2 * old single-process version of dial that libthread can cope with
3 */
4 #include <u.h>
5 #include <libc.h>
6
7 typedef struct DS DS;
8
9 static int call(char*, char*, DS*);
10 static int csdial(DS*);
11 static void _dial_string_parse(char*, DS*);
12
13 enum
14 {
15 Maxstring = 128,
16 Maxpath = 256,
17 };
18
19 struct DS {
20 /* dist string */
21 char buf[Maxstring];
22 char *netdir;
23 char *proto;
24 char *rem;
25
26 /* other args */
27 char *local;
28 char *dir;
29 int *cfdp;
30 };
31
32
33 /*
34 * the dialstring is of the form '[/net/]proto!dest'
35 */
36 int
_threaddial(char * dest,char * local,char * dir,int * cfdp)37 _threaddial(char *dest, char *local, char *dir, int *cfdp)
38 {
39 DS ds;
40 int rv;
41 char err[ERRMAX], alterr[ERRMAX];
42
43 ds.local = local;
44 ds.dir = dir;
45 ds.cfdp = cfdp;
46
47 _dial_string_parse(dest, &ds);
48 if(ds.netdir)
49 return csdial(&ds);
50
51 ds.netdir = "/net";
52 rv = csdial(&ds);
53 if(rv >= 0)
54 return rv;
55 err[0] = '\0';
56 errstr(err, sizeof err);
57 if(strstr(err, "refused") != 0){
58 werrstr("%s", err);
59 return rv;
60 }
61 ds.netdir = "/net.alt";
62 rv = csdial(&ds);
63 if(rv >= 0)
64 return rv;
65
66 alterr[0] = 0;
67 errstr(alterr, sizeof alterr);
68 if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
69 werrstr("%s", err);
70 else
71 werrstr("%s", alterr);
72 return rv;
73 }
74
75 static int
csdial(DS * ds)76 csdial(DS *ds)
77 {
78 int n, fd, rv;
79 char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
80
81 /*
82 * open connection server
83 */
84 snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
85 fd = open(buf, ORDWR);
86 if(fd < 0){
87 /* no connection server, don't translate */
88 snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
89 return call(clone, ds->rem, ds);
90 }
91
92 /*
93 * ask connection server to translate
94 */
95 snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
96 if(write(fd, buf, strlen(buf)) < 0){
97 close(fd);
98 return -1;
99 }
100
101 /*
102 * loop through each address from the connection server till
103 * we get one that works.
104 */
105 *besterr = 0;
106 rv = -1;
107 seek(fd, 0, 0);
108 while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
109 buf[n] = 0;
110 p = strchr(buf, ' ');
111 if(p == 0)
112 continue;
113 *p++ = 0;
114 rv = call(buf, p, ds);
115 if(rv >= 0)
116 break;
117 err[0] = '\0';
118 errstr(err, sizeof err);
119 if(strstr(err, "does not exist") == 0)
120 strcpy(besterr, err);
121 }
122 close(fd);
123
124 if(rv < 0 && *besterr)
125 werrstr("%s", besterr);
126 else
127 werrstr("%s", err);
128 return rv;
129 }
130
131 static int
call(char * clone,char * dest,DS * ds)132 call(char *clone, char *dest, DS *ds)
133 {
134 int fd, cfd, n;
135 char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
136
137 /* because cs is in a different name space, replace the mount point */
138 if(*clone == '/'){
139 p = strchr(clone+1, '/');
140 if(p == nil)
141 p = clone;
142 else
143 p++;
144 } else
145 p = clone;
146 snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
147
148 cfd = open(cname, ORDWR);
149 if(cfd < 0)
150 return -1;
151
152 /* get directory name */
153 n = read(cfd, name, sizeof(name)-1);
154 if(n < 0){
155 close(cfd);
156 return -1;
157 }
158 name[n] = 0;
159 for(p = name; *p == ' '; p++)
160 ;
161 snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
162 p = strrchr(cname, '/');
163 *p = 0;
164 if(ds->dir)
165 snprint(ds->dir, NETPATHLEN, "%s/%s", cname, name);
166 snprint(data, sizeof(data), "%s/%s/data", cname, name);
167
168 /* connect */
169 if(ds->local)
170 snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
171 else
172 snprint(name, sizeof(name), "connect %s", dest);
173 if(write(cfd, name, strlen(name)) < 0){
174 close(cfd);
175 return -1;
176 }
177
178 /* open data connection */
179 fd = open(data, ORDWR);
180 if(fd < 0){
181 close(cfd);
182 return -1;
183 }
184 if(ds->cfdp)
185 *ds->cfdp = cfd;
186 else
187 close(cfd);
188 return fd;
189 }
190
191 /*
192 * parse a dial string
193 */
194 static void
_dial_string_parse(char * str,DS * ds)195 _dial_string_parse(char *str, DS *ds)
196 {
197 char *p, *p2;
198
199 strncpy(ds->buf, str, Maxstring);
200 ds->buf[Maxstring-1] = 0;
201
202 p = strchr(ds->buf, '!');
203 if(p == 0) {
204 ds->netdir = 0;
205 ds->proto = "net";
206 ds->rem = ds->buf;
207 } else {
208 if(*ds->buf != '/' && *ds->buf != '#'){
209 ds->netdir = 0;
210 ds->proto = ds->buf;
211 } else {
212 for(p2 = p; *p2 != '/'; p2--)
213 ;
214 *p2++ = 0;
215 ds->netdir = ds->buf;
216 ds->proto = p2;
217 }
218 *p = 0;
219 ds->rem = p + 1;
220 }
221 }
222