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