tvftp.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tvftp.c (8483B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <bio.h> | |
4 #include <thread.h> | |
5 #include <venti.h> | |
6 #include <sunrpc.h> | |
7 #include <nfs3.h> | |
8 #include <diskfs.h> | |
9 | |
10 uchar *buf; | |
11 uint bufsize; | |
12 Nfs3Handle cwd, root; | |
13 Biobuf bin, bout; | |
14 char pwd[1000]; | |
15 Fsys *fsys; | |
16 SunAuthUnix *auth; | |
17 VtConn *z; | |
18 VtCache *c; | |
19 Disk *disk; | |
20 | |
21 char *cmdhelp(int, char**); | |
22 char *cmdcd(int, char**); | |
23 char *cmdpwd(int, char**); | |
24 char *cmdls(int, char**); | |
25 char *cmdget(int, char**); | |
26 char *cmdblock(int, char**); | |
27 char *cmddisk(int, char**); | |
28 | |
29 typedef struct Cmd Cmd; | |
30 struct Cmd | |
31 { | |
32 char *s; | |
33 char *(*fn)(int, char**); | |
34 char *help; | |
35 }; | |
36 | |
37 Cmd cmdtab[] = | |
38 { | |
39 "cd", cmdcd, "cd dir - change directory", | |
40 "ls", cmdls, "ls [-d] path... - list file", | |
41 "get", cmdget, "get path [lpath] - copy file to local directory", | |
42 "pwd", cmdpwd, "pwd - print working directory", | |
43 "help", cmdhelp, "help - print usage summaries", | |
44 "block", cmdblock, "block path offset - print disk offset of pat… | |
45 "disk", cmddisk, "disk offset count - dump disk contents" | |
46 }; | |
47 | |
48 char* | |
49 ebuf(void) | |
50 { | |
51 static char buf[ERRMAX]; | |
52 | |
53 rerrstr(buf, sizeof buf); | |
54 return buf; | |
55 } | |
56 | |
57 static char* | |
58 estrdup(char *s) | |
59 { | |
60 char *t; | |
61 | |
62 t = emalloc(strlen(s)+1); | |
63 strcpy(t, s); | |
64 return t; | |
65 } | |
66 | |
67 char* | |
68 walk(char *path, Nfs3Handle *ph) | |
69 { | |
70 char *p, *q; | |
71 Nfs3Handle h; | |
72 Nfs3Status ok; | |
73 | |
74 path = estrdup(path); /* writable */ | |
75 if(path[0] == '/') | |
76 h = root; | |
77 else | |
78 h = cwd; | |
79 for(p=path; *p; p=q){ | |
80 q = strchr(p, '/'); | |
81 if(q == nil) | |
82 q = p+strlen(p); | |
83 else | |
84 *q++ = 0; | |
85 if(*p == 0) | |
86 continue; | |
87 if((ok = fsyslookup(fsys, auth, &h, p, &h)) != Nfs3Ok){ | |
88 nfs3errstr(ok); | |
89 free(path); | |
90 return ebuf(); | |
91 } | |
92 } | |
93 *ph = h; | |
94 free(path); | |
95 return nil; | |
96 } | |
97 | |
98 char* | |
99 cmdhelp(int argc, char **argv) | |
100 { | |
101 int i; | |
102 | |
103 for(i=0; i<nelem(cmdtab); i++) | |
104 print("%s\n", cmdtab[i].help); | |
105 return nil; | |
106 } | |
107 | |
108 char* | |
109 cmdcd(int argc, char **argv) | |
110 { | |
111 char *err; | |
112 Nfs3Attr attr; | |
113 Nfs3Status ok; | |
114 Nfs3Handle h; | |
115 | |
116 if(argc != 2) | |
117 return "usage: cd dir"; | |
118 | |
119 if((err = walk(argv[1], &h)) != nil) | |
120 return err; | |
121 if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){ | |
122 nfs3errstr(ok); | |
123 fprint(2, "%s: %r\n", argv[1]); | |
124 return nil; | |
125 } | |
126 if(attr.type != Nfs3FileDir) | |
127 return "not a directory"; | |
128 if(argv[1][0] == '/') | |
129 pwd[0] = 0; | |
130 strcat(pwd, "/"); | |
131 strcat(pwd, argv[1]); | |
132 cleanname(pwd); | |
133 cwd = h; | |
134 print("%s\n", pwd); | |
135 return nil; | |
136 } | |
137 | |
138 char* | |
139 cmdpwd(int argc, char **argv) | |
140 { | |
141 if(argc != 1) | |
142 return "usage: pwd"; | |
143 | |
144 print("%s\n", pwd); | |
145 return nil; | |
146 } | |
147 | |
148 /* | |
149 * XXX maybe make a list of these in memory and then print them nicer | |
150 */ | |
151 void | |
152 ls(char *dir, char *elem, Nfs3Attr *attr) | |
153 { | |
154 char c; | |
155 | |
156 c = ' '; /* use attr->type */ | |
157 Bprint(&bout, "%s%s%s", dir ? dir : "", dir && elem ? "/" : "", … | |
158 Bprint(&bout, " %c%luo %1d %4d %4d", c, attr->mode, attr->nlink,… | |
159 Bprint(&bout, " %11,lld %11,lld %4d.%4d %#11,llux %#11,llux", | |
160 attr->size, attr->used, attr->major, attr->minor, attr->… | |
161 Bprint(&bout, "\n"); | |
162 } | |
163 | |
164 void | |
165 lsdir(char *dir, Nfs3Handle *h) | |
166 { | |
167 uchar *data, *p, *ep; | |
168 Nfs3Attr attr; | |
169 Nfs3Entry e; | |
170 Nfs3Handle eh; | |
171 u32int count; | |
172 u1int eof; | |
173 Nfs3Status ok; | |
174 u64int cookie; | |
175 | |
176 cookie = 0; | |
177 for(;;){ | |
178 ok = fsysreaddir(fsys, auth, h, 8192, cookie, &data, &co… | |
179 if(ok != Nfs3Ok){ | |
180 nfs3errstr(ok); | |
181 fprint(2, "ls %s: %r\n", dir); | |
182 return; | |
183 } | |
184 fprint(2, "got %d\n", count); | |
185 p = data; | |
186 ep = data+count; | |
187 while(p<ep){ | |
188 if(nfs3entryunpack(p, ep, &p, &e) < 0){ | |
189 fprint(2, "%s: unpacking directory: %r\n… | |
190 break; | |
191 } | |
192 cookie = e.cookie; | |
193 if((ok = fsyslookup(fsys, auth, h, e.name, &eh))… | |
194 nfs3errstr(ok); | |
195 fprint(2, "%s/%s: %r\n", dir, e.name); | |
196 continue; | |
197 } | |
198 if((ok = fsysgetattr(fsys, auth, &eh, &attr)) !=… | |
199 nfs3errstr(ok); | |
200 fprint(2, "%s/%s: %r\n", dir, e.name); | |
201 continue; | |
202 } | |
203 ls(dir, e.name, &attr); | |
204 } | |
205 free(data); | |
206 if(eof) | |
207 break; | |
208 } | |
209 } | |
210 | |
211 char* | |
212 cmdls(int argc, char **argv) | |
213 { | |
214 int i; | |
215 int dflag; | |
216 char *e; | |
217 Nfs3Handle h; | |
218 Nfs3Attr attr; | |
219 Nfs3Status ok; | |
220 | |
221 dflag = 0; | |
222 ARGBEGIN{ | |
223 case 'd': | |
224 dflag = 1; | |
225 break; | |
226 default: | |
227 return "usage: ls [-d] [path...]"; | |
228 }ARGEND | |
229 | |
230 if(argc == 0){ | |
231 lsdir(nil, &cwd); | |
232 Bflush(&bout); | |
233 return nil; | |
234 } | |
235 | |
236 for(i=0; i<argc; i++){ | |
237 if((e = walk(argv[i], &h)) != nil){ | |
238 fprint(2, "%s: %s\n", argv[i], e); | |
239 continue; | |
240 } | |
241 if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){ | |
242 nfs3errstr(ok); | |
243 fprint(2, "%s: %r\n", argv[i]); | |
244 continue; | |
245 } | |
246 if(attr.type != Nfs3FileDir || dflag) | |
247 ls(argv[i], nil, &attr); | |
248 else | |
249 lsdir(argv[i], &h); | |
250 Bflush(&bout); | |
251 } | |
252 return nil; | |
253 } | |
254 | |
255 char* | |
256 cmdget(int argc, char **argv) | |
257 { | |
258 uchar eof; | |
259 u32int n; | |
260 int dflag, fd; | |
261 char *e, *local; | |
262 uchar *buf; | |
263 Nfs3Handle h; | |
264 Nfs3Attr attr; | |
265 Nfs3Status ok; | |
266 vlong o; | |
267 | |
268 dflag = 0; | |
269 ARGBEGIN{ | |
270 default: | |
271 usage: | |
272 return "usage: get path [lpath]]"; | |
273 }ARGEND | |
274 | |
275 if(argc != 1 && argc != 2) | |
276 goto usage; | |
277 | |
278 if((e = walk(argv[0], &h)) != nil){ | |
279 fprint(2, "%s: %s\n", argv[0], e); | |
280 return nil; | |
281 } | |
282 if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){ | |
283 nfs3errstr(ok); | |
284 fprint(2, "%s: %r\n", argv[0]); | |
285 return nil; | |
286 } | |
287 local = argv[0]; | |
288 if(argc == 2) | |
289 local = argv[1]; | |
290 if((fd = create(local, OWRITE, 0666)) < 0){ | |
291 fprint(2, "create %s: %r\n", local); | |
292 return nil; | |
293 } | |
294 eof = 0; | |
295 for(o=0; o<attr.size && !eof; o+=n){ | |
296 if((ok = fsysreadfile(fsys, nil, &h, fsys->blocksize, o,… | |
297 nfs3errstr(ok); | |
298 fprint(2, "reading %s: %r\n", argv[0]); | |
299 close(fd); | |
300 return nil; | |
301 } | |
302 if(write(fd, buf, n) != n){ | |
303 fprint(2, "writing %s: %r\n", local); | |
304 close(fd); | |
305 free(buf); | |
306 return nil; | |
307 } | |
308 free(buf); | |
309 } | |
310 close(fd); | |
311 fprint(2, "copied %,lld bytes\n", o); | |
312 return nil; | |
313 } | |
314 | |
315 | |
316 char* | |
317 cmdblock(int argc, char **argv) | |
318 { | |
319 char *e; | |
320 Nfs3Handle h; | |
321 u64int bno; | |
322 | |
323 ARGBEGIN{ | |
324 default: | |
325 return "usage: block path offset"; | |
326 }ARGEND | |
327 | |
328 if(argc != 2) | |
329 return "usage: block path offset"; | |
330 | |
331 if((e = walk(argv[0], &h)) != nil){ | |
332 fprint(2, "%s: %s\n", argv[0], e); | |
333 return nil; | |
334 } | |
335 if((bno = fsys->fileblock(fsys, &h, strtoll(argv[1], 0, 0))) == … | |
336 fprint(2, "%s: %r\n", argv[0]); | |
337 return nil; | |
338 } | |
339 print("%#llux\n", bno); | |
340 return nil; | |
341 } | |
342 | |
343 char* | |
344 cmddisk(int argc, char **argv) | |
345 { | |
346 Block *b; | |
347 int delta, count, i; | |
348 u64int offset; | |
349 uchar *p; | |
350 | |
351 ARGBEGIN{ | |
352 default: | |
353 return "usage: disk offset count"; | |
354 }ARGEND | |
355 | |
356 if(argc != 2) | |
357 return "usage: disk offset count"; | |
358 | |
359 offset = strtoull(argv[0], 0, 0); | |
360 count = atoi(argv[1]); | |
361 delta = offset%fsys->blocksize; | |
362 | |
363 b = diskread(disk, fsys->blocksize, offset-delta); | |
364 if(b == nil){ | |
365 fprint(2, "diskread: %r\n"); | |
366 return nil; | |
367 } | |
368 p = b->data + delta; | |
369 for(i=0; i<count; i++){ | |
370 Bprint(&bout, "%2.2ux ", p[i]); | |
371 if(i%16 == 15) | |
372 Bprint(&bout, "\n"); | |
373 else if(i%8 == 7) | |
374 Bprint(&bout, " - "); | |
375 } | |
376 if(i%16 != 0) | |
377 Bprint(&bout, "\n"); | |
378 Bflush(&bout); | |
379 blockput(b); | |
380 return nil; | |
381 } | |
382 | |
383 void | |
384 usage(void) | |
385 { | |
386 fprint(2, "usage: vftp score\n"); | |
387 threadexitsall("usage"); | |
388 } | |
389 | |
390 extern int allowall; | |
391 | |
392 void | |
393 threadmain(int argc, char **argv) | |
394 { | |
395 char *err, *f[10], *p; | |
396 int i, nf; | |
397 uchar score[VtScoreSize]; | |
398 Nfs3Status ok; | |
399 | |
400 allowall = 1; | |
401 ARGBEGIN{ | |
402 case 'V': | |
403 chattyventi++; | |
404 break; | |
405 default: | |
406 usage(); | |
407 }ARGEND | |
408 | |
409 if(argc != 1) | |
410 usage(); | |
411 | |
412 fmtinstall('F', vtfcallfmt); | |
413 fmtinstall('H', encodefmt); | |
414 fmtinstall('V', vtscorefmt); | |
415 | |
416 if(access(argv[0], AEXIST) >= 0 || strchr(argv[0], '/')){ | |
417 if((disk = diskopenfile(argv[0])) == nil) | |
418 sysfatal("diskopen: %r"); | |
419 if((disk = diskcache(disk, 32768, 16)) == nil) | |
420 sysfatal("diskcache: %r"); | |
421 }else{ | |
422 if(vtparsescore(argv[0], nil, score) < 0) | |
423 sysfatal("bad score '%s'", argv[0]); | |
424 if((z = vtdial(nil)) == nil) | |
425 sysfatal("vtdial: %r"); | |
426 if(vtconnect(z) < 0) | |
427 sysfatal("vtconnect: %r"); | |
428 if((c = vtcachealloc(z, 32768, 32)) == nil) | |
429 sysfatal("vtcache: %r"); | |
430 if((disk = diskopenventi(c, score)) == nil) | |
431 sysfatal("diskopenventi: %r"); | |
432 } | |
433 if((fsys = fsysopen(disk)) == nil) | |
434 sysfatal("fsysopen: %r"); | |
435 | |
436 fprint(2, "block size %d\n", fsys->blocksize); | |
437 buf = emalloc(fsys->blocksize); | |
438 if((ok = fsysroot(fsys, &root)) != Nfs3Ok){ | |
439 nfs3errstr(ok); | |
440 sysfatal("accessing root: %r"); | |
441 } | |
442 cwd = root; | |
443 Binit(&bin, 0, OREAD); | |
444 Binit(&bout, 1, OWRITE); | |
445 | |
446 while(fprint(2, "vftp> "), (p = Brdstr(&bin, '\n', 1)) != nil){ | |
447 if(p[0] == '#') | |
448 continue; | |
449 nf = tokenize(p, f, nelem(f)); | |
450 if(nf == 0) | |
451 continue; | |
452 for(i=0; i<nelem(cmdtab); i++){ | |
453 if(strcmp(f[0], cmdtab[i].s) == 0){ | |
454 if((err = cmdtab[i].fn(nf, f)) != nil) | |
455 fprint(2, "%s\n", err); | |
456 break; | |
457 } | |
458 } | |
459 if(i == nelem(cmdtab)) | |
460 fprint(2, "unknown command '%s'\n", f[0]); | |
461 } | |
462 threadexitsall(nil); | |
463 } |